diff --git a/.gitignore b/.gitignore index 2a459583a..a23ef2db8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -linux-*.tar.bz2 -patch-*.bz2 clog +*.xz +*.bz2 *.rpm +*.orig kernel-[23].*/ diff --git a/0001-ACPI-sony-laptop-do-proper-memcpy-for-ACPI_TYPE_INTE.patch b/0001-ACPI-sony-laptop-do-proper-memcpy-for-ACPI_TYPE_INTE.patch new file mode 100644 index 000000000..857c73c51 --- /dev/null +++ b/0001-ACPI-sony-laptop-do-proper-memcpy-for-ACPI_TYPE_INTE.patch @@ -0,0 +1,50 @@ +From 690b1ad9d2032d6f2565d44f6564590d47835ae8 Mon Sep 17 00:00:00 2001 +From: Zhang Rui +Date: Thu, 29 Nov 2012 01:30:43 +0800 +Subject: [PATCH 1/2] ACPI sony-laptop: do proper memcpy for ACPI_TYPE_INTEGER + acpi_object + +the return value of __call_snc_method can either be +an ACPI_TYPE_BUFFER object or a ACPI_TYPE_INTEGER object. +do proper memcpy for ACPI_TYPE_INTEGER object. + +https://bugzilla.kernel.org/show_bug.cgi?id=50111 + +Signed-off-by: Zhang Rui +--- + drivers/platform/x86/sony-laptop.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c +index daaddec..92e0da2 100644 +--- a/drivers/platform/x86/sony-laptop.c ++++ b/drivers/platform/x86/sony-laptop.c +@@ -792,20 +792,19 @@ static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, + if (!object) + return -EINVAL; + +- if (object->type == ACPI_TYPE_BUFFER) ++ if (object->type == ACPI_TYPE_BUFFER) { + len = MIN(buflen, object->buffer.length); +- +- else if (object->type == ACPI_TYPE_INTEGER) ++ memcpy(buffer, object->buffer.pointer, len); ++ } else if (object->type == ACPI_TYPE_INTEGER) { + len = MIN(buflen, sizeof(object->integer.value)); +- +- else { ++ memcpy(buffer, (void *)&object->integer.value, len); ++ } else { + pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", + ACPI_TYPE_BUFFER, object->type); + kfree(object); + return -EINVAL; + } + +- memcpy(buffer, object->buffer.pointer, len); + kfree(object); + return 0; + } +-- +1.7.9.5 + diff --git a/0001-ext4-ext4_inode_info-diet.patch b/0001-ext4-ext4_inode_info-diet.patch new file mode 100644 index 000000000..c7858ecc6 --- /dev/null +++ b/0001-ext4-ext4_inode_info-diet.patch @@ -0,0 +1,121 @@ +From 50b61634cf8d09f9ef334919b859735d381cbe39 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 28 Sep 2012 23:21:09 -0400 +Subject: [PATCH 01/13] ext4: ext4_inode_info diet + +Generic inode has unused i_private pointer which may be used as cur_aio_dio +storage. + +TODO: If cur_aio_dio will be passed as an argument to get_block_t this allow + to have concurent AIO_DIO requests. + +Reviewed-by: Zheng Liu +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit f45ee3a1ea438af96e4fd2c0b16d195e67ef235f) +--- + fs/ext4/ext4.h | 12 ++++++++++-- + fs/ext4/extents.c | 4 ++-- + fs/ext4/inode.c | 6 +++--- + fs/ext4/super.c | 1 - + 4 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index c3411d4..80afc8f 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -912,8 +912,6 @@ struct ext4_inode_info { + struct list_head i_completed_io_list; + spinlock_t i_completed_io_lock; + atomic_t i_ioend_count; /* Number of outstanding io_end structs */ +- /* current io_end structure for async DIO write*/ +- ext4_io_end_t *cur_aio_dio; + atomic_t i_aiodio_unwritten; /* Nr. of inflight conversions pending */ + + spinlock_t i_block_reservation_lock; +@@ -1332,6 +1330,16 @@ static inline void ext4_set_io_unwritten_flag(struct inode *inode, + } + } + ++static inline ext4_io_end_t *ext4_inode_aio(struct inode *inode) ++{ ++ return inode->i_private; ++} ++ ++static inline void ext4_inode_aio_set(struct inode *inode, ext4_io_end_t *io) ++{ ++ inode->i_private = io; ++} ++ + /* + * Inode dynamic state flags + */ +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index aabbb3f..51fbef1 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -3600,7 +3600,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, + { + int ret = 0; + int err = 0; +- ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio; ++ ext4_io_end_t *io = ext4_inode_aio(inode); + + ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical " + "block %llu, max_blocks %u, flags %x, allocated %u\n", +@@ -3858,7 +3858,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, + unsigned int allocated = 0, offset = 0; + unsigned int allocated_clusters = 0; + struct ext4_allocation_request ar; +- ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio; ++ ext4_io_end_t *io = ext4_inode_aio(inode); + ext4_lblk_t cluster_offset; + + ext_debug("blocks %u/%u requested for inode %lu\n", +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index dff171c..acadd2b 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3054,7 +3054,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, + * hook to the iocb. + */ + iocb->private = NULL; +- EXT4_I(inode)->cur_aio_dio = NULL; ++ ext4_inode_aio_set(inode, NULL); + if (!is_sync_kiocb(iocb)) { + ext4_io_end_t *io_end = + ext4_init_io_end(inode, GFP_NOFS); +@@ -3071,7 +3071,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, + * is a unwritten extents needs to be converted + * when IO is completed. + */ +- EXT4_I(inode)->cur_aio_dio = iocb->private; ++ ext4_inode_aio_set(inode, io_end); + } + + if (overwrite) +@@ -3091,7 +3091,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, + NULL, + DIO_LOCKING); + if (iocb->private) +- EXT4_I(inode)->cur_aio_dio = NULL; ++ ext4_inode_aio_set(inode, NULL); + /* + * The io_end structure takes a reference to the inode, + * that structure needs to be destroyed and the +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index c6e0cb3..270e58f 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -956,7 +956,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) + ei->jinode = NULL; + INIT_LIST_HEAD(&ei->i_completed_io_list); + spin_lock_init(&ei->i_completed_io_lock); +- ei->cur_aio_dio = NULL; + ei->i_sync_tid = 0; + ei->i_datasync_tid = 0; + atomic_set(&ei->i_ioend_count, 0); +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0002-ext4-give-i_aiodio_unwritten-a-more-appropriate-name.patch b/0002-ext4-give-i_aiodio_unwritten-a-more-appropriate-name.patch new file mode 100644 index 000000000..cfd13f386 --- /dev/null +++ b/0002-ext4-give-i_aiodio_unwritten-a-more-appropriate-name.patch @@ -0,0 +1,97 @@ +From 027d1aa67e32c2c80851105c6d962f3db46eb476 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 28 Sep 2012 23:24:52 -0400 +Subject: [PATCH 02/13] ext4: give i_aiodio_unwritten a more appropriate name + +AIO/DIO prefix is wrong because it account unwritten extents which +also may be scheduled from buffered write endio + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit e27f41e1b789e60e7d8cc9c81fd93ca49ef31f13) +--- + fs/ext4/ext4.h | 4 ++-- + fs/ext4/file.c | 6 +++--- + fs/ext4/page-io.c | 2 +- + fs/ext4/super.c | 2 +- + 4 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 80afc8f..28dfd9b 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -912,7 +912,7 @@ struct ext4_inode_info { + struct list_head i_completed_io_list; + spinlock_t i_completed_io_lock; + atomic_t i_ioend_count; /* Number of outstanding io_end structs */ +- atomic_t i_aiodio_unwritten; /* Nr. of inflight conversions pending */ ++ atomic_t i_unwritten; /* Nr. of inflight conversions pending */ + + spinlock_t i_block_reservation_lock; + +@@ -1326,7 +1326,7 @@ static inline void ext4_set_io_unwritten_flag(struct inode *inode, + { + if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { + io_end->flag |= EXT4_IO_END_UNWRITTEN; +- atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten); ++ atomic_inc(&EXT4_I(inode)->i_unwritten); + } + } + +diff --git a/fs/ext4/file.c b/fs/ext4/file.c +index 3b0e3bd..39335bd 100644 +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -55,11 +55,11 @@ static int ext4_release_file(struct inode *inode, struct file *filp) + return 0; + } + +-static void ext4_aiodio_wait(struct inode *inode) ++static void ext4_unwritten_wait(struct inode *inode) + { + wait_queue_head_t *wq = ext4_ioend_wq(inode); + +- wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_aiodio_unwritten) == 0)); ++ wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_unwritten) == 0)); + } + + /* +@@ -116,7 +116,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, + "performance will be poor.", + inode->i_ino, current->comm); + mutex_lock(ext4_aio_mutex(inode)); +- ext4_aiodio_wait(inode); ++ ext4_unwritten_wait(inode); + } + + BUG_ON(iocb->ki_pos != pos); +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index dcdeef1..de77e31 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -113,7 +113,7 @@ int ext4_end_io_nolock(ext4_io_end_t *io) + if (io->flag & EXT4_IO_END_DIRECT) + inode_dio_done(inode); + /* Wake up anyone waiting on unwritten extent conversion */ +- if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten)) ++ if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) + wake_up_all(ext4_ioend_wq(io->inode)); + return ret; + } +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 270e58f..1b6b425 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -959,7 +959,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) + ei->i_sync_tid = 0; + ei->i_datasync_tid = 0; + atomic_set(&ei->i_ioend_count, 0); +- atomic_set(&ei->i_aiodio_unwritten, 0); ++ atomic_set(&ei->i_unwritten, 0); + + return &ei->vfs_inode; + } +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0003-ext4-fix-unwritten-counter-leakage.patch b/0003-ext4-fix-unwritten-counter-leakage.patch new file mode 100644 index 000000000..2f1d0d813 --- /dev/null +++ b/0003-ext4-fix-unwritten-counter-leakage.patch @@ -0,0 +1,112 @@ +From 6a0e905bb7320571ed5fdd2d5efa3d642630b4f7 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 28 Sep 2012 23:36:25 -0400 +Subject: [PATCH 03/13] ext4: fix unwritten counter leakage + +ext4_set_io_unwritten_flag() will increment i_unwritten counter, so +once we mark end_io with EXT4_END_IO_UNWRITTEN we have to revert it back +on error path. + + - add missed error checks to prevent counter leakage + - ext4_end_io_nolock() will clear EXT4_END_IO_UNWRITTEN flag to signal + that conversion finished. + - add BUG_ON to ext4_free_end_io() to prevent similar leakage in future. + +Visible effect of this bug is that unaligned aio_stress may deadlock + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 82e54229118785badffb4ef5ba4803df25fe007f) +--- + fs/ext4/extents.c | 21 ++++++++++++++------- + fs/ext4/page-io.c | 6 +++++- + 2 files changed, 19 insertions(+), 8 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 51fbef1..e04eb4f 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -3615,6 +3615,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, + if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { + ret = ext4_split_unwritten_extents(handle, inode, map, + path, flags); ++ if (ret <= 0) ++ goto out; + /* + * Flag the inode(non aio case) or end_io struct (aio case) + * that this IO needs to conversion to written when IO is +@@ -3860,6 +3862,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, + struct ext4_allocation_request ar; + ext4_io_end_t *io = ext4_inode_aio(inode); + ext4_lblk_t cluster_offset; ++ int set_unwritten = 0; + + ext_debug("blocks %u/%u requested for inode %lu\n", + map->m_lblk, map->m_len, inode->i_ino); +@@ -4082,13 +4085,8 @@ got_allocated_blocks: + * For non asycn direct IO case, flag the inode state + * that we need to perform conversion when IO is done. + */ +- if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { +- if (io) +- ext4_set_io_unwritten_flag(inode, io); +- else +- ext4_set_inode_state(inode, +- EXT4_STATE_DIO_UNWRITTEN); +- } ++ if ((flags & EXT4_GET_BLOCKS_PRE_IO)) ++ set_unwritten = 1; + if (ext4_should_dioread_nolock(inode)) + map->m_flags |= EXT4_MAP_UNINIT; + } +@@ -4100,6 +4098,15 @@ got_allocated_blocks: + if (!err) + err = ext4_ext_insert_extent(handle, inode, path, + &newex, flags); ++ ++ if (!err && set_unwritten) { ++ if (io) ++ ext4_set_io_unwritten_flag(inode, io); ++ else ++ ext4_set_inode_state(inode, ++ EXT4_STATE_DIO_UNWRITTEN); ++ } ++ + if (err && free_on_err) { + int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? + EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index de77e31..9970022 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -71,6 +71,8 @@ void ext4_free_io_end(ext4_io_end_t *io) + int i; + + BUG_ON(!io); ++ BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); ++ + if (io->page) + put_page(io->page); + for (i = 0; i < io->num_io_pages; i++) +@@ -94,6 +96,8 @@ int ext4_end_io_nolock(ext4_io_end_t *io) + ssize_t size = io->size; + int ret = 0; + ++ BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN)); ++ + ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p," + "list->prev 0x%p\n", + io, inode->i_ino, io->list.next, io->list.prev); +@@ -106,7 +110,7 @@ int ext4_end_io_nolock(ext4_io_end_t *io) + "(inode %lu, offset %llu, size %zd, error %d)", + inode->i_ino, offset, size, ret); + } +- ++ io->flag &= ~EXT4_IO_END_UNWRITTEN; + if (io->iocb) + aio_complete(io->iocb, io->result, 0); + +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0004-ext4-completed_io-locking-cleanup.patch b/0004-ext4-completed_io-locking-cleanup.patch new file mode 100644 index 000000000..a358a7952 --- /dev/null +++ b/0004-ext4-completed_io-locking-cleanup.patch @@ -0,0 +1,520 @@ +From e23394806df0768ed2dac87484590d2f3a730d55 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sat, 29 Sep 2012 00:14:55 -0400 +Subject: [PATCH 04/13] ext4: completed_io locking cleanup + +Current unwritten extent conversion state-machine is very fuzzy. +- For unknown reason it performs conversion under i_mutex. What for? + My diagnosis: + We already protect extent tree with i_data_sem, truncate and punch_hole + should wait for DIO, so the only data we have to protect is end_io->flags + modification, but only flush_completed_IO and end_io_work modified this + flags and we can serialize them via i_completed_io_lock. + + Currently all these games with mutex_trylock result in the following deadlock + truncate: kworker: + ext4_setattr ext4_end_io_work + mutex_lock(i_mutex) + inode_dio_wait(inode) ->BLOCK + DEADLOCK<- mutex_trylock() + inode_dio_done() + #TEST_CASE1_BEGIN + MNT=/mnt_scrach + unlink $MNT/file + fallocate -l $((1024*1024*1024)) $MNT/file + aio-stress -I 100000 -O -s 100m -n -t 1 -c 10 -o 2 -o 3 $MNT/file + sleep 2 + truncate -s 0 $MNT/file + #TEST_CASE1_END + +Or use 286's xfstests https://github.com/dmonakhov/xfstests/blob/devel/286 + +This patch makes state machine simple and clean: + +(1) xxx_end_io schedule final extent conversion simply by calling + ext4_add_complete_io(), which append it to ei->i_completed_io_list + NOTE1: because of (2A) work should be queued only if + ->i_completed_io_list was empty, otherwise the work is scheduled already. + +(2) ext4_flush_completed_IO is responsible for handling all pending + end_io from ei->i_completed_io_list + Flushing sequence consists of following stages: + A) LOCKED: Atomically drain completed_io_list to local_list + B) Perform extents conversion + C) LOCKED: move converted io's to to_free list for final deletion + This logic depends on context which we was called from. + D) Final end_io context destruction + NOTE1: i_mutex is no longer required because end_io->flags modification + is protected by ei->ext4_complete_io_lock + +Full list of changes: +- Move all completion end_io related routines to page-io.c in order to improve + logic locality +- Move open coded logic from various xx_end_xx routines to ext4_add_complete_io() +- remove EXT4_IO_END_FSYNC +- Improve SMP scalability by removing useless i_mutex which does not + protect io->flags anymore. +- Reduce lock contention on i_completed_io_lock by optimizing list walk. +- Rename ext4_end_io_nolock to end4_end_io and make it static +- Check flush completion status to ext4_ext_punch_hole(). Because it is + not good idea to punch blocks from corrupted inode. + +Changes since V3 (in request to Jan's comments): + Fall back to active flush_completed_IO() approach in order to prevent + performance issues with nolocked DIO reads. +Changes since V2: + Fix use-after-free caused by race truncate vs end_io_work + +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 28a535f9a0df060569dcc786e5bc2e1de43d7dc7) +--- + fs/ext4/ext4.h | 3 +- + fs/ext4/extents.c | 4 +- + fs/ext4/fsync.c | 81 ------------------------- + fs/ext4/indirect.c | 6 +- + fs/ext4/inode.c | 25 +------- + fs/ext4/page-io.c | 171 +++++++++++++++++++++++++++++++++++------------------ + 6 files changed, 121 insertions(+), 169 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 28dfd9b..7687d15 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -186,7 +186,6 @@ struct mpage_da_data { + #define EXT4_IO_END_ERROR 0x0002 + #define EXT4_IO_END_QUEUED 0x0004 + #define EXT4_IO_END_DIRECT 0x0008 +-#define EXT4_IO_END_IN_FSYNC 0x0010 + + struct ext4_io_page { + struct page *p_page; +@@ -2408,11 +2407,11 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, + + /* page-io.c */ + extern int __init ext4_init_pageio(void); ++extern void ext4_add_complete_io(ext4_io_end_t *io_end); + extern void ext4_exit_pageio(void); + extern void ext4_ioend_wait(struct inode *); + extern void ext4_free_io_end(ext4_io_end_t *io); + extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); +-extern int ext4_end_io_nolock(ext4_io_end_t *io); + extern void ext4_io_submit(struct ext4_io_submit *io); + extern int ext4_bio_write_page(struct ext4_io_submit *io, + struct page *page, +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index e04eb4f..1fbf2ff 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4815,7 +4815,9 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) + } + + /* finish any pending end_io work */ +- ext4_flush_completed_IO(inode); ++ err = ext4_flush_completed_IO(inode); ++ if (err) ++ return err; + + credits = ext4_writepage_trans_blocks(inode); + handle = ext4_journal_start(inode, credits); +diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c +index 2a1dcea..520b058 100644 +--- a/fs/ext4/fsync.c ++++ b/fs/ext4/fsync.c +@@ -34,87 +34,6 @@ + + #include + +-static void dump_completed_IO(struct inode * inode) +-{ +-#ifdef EXT4FS_DEBUG +- struct list_head *cur, *before, *after; +- ext4_io_end_t *io, *io0, *io1; +- unsigned long flags; +- +- if (list_empty(&EXT4_I(inode)->i_completed_io_list)){ +- ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino); +- return; +- } +- +- ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino); +- spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); +- list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){ +- cur = &io->list; +- before = cur->prev; +- io0 = container_of(before, ext4_io_end_t, list); +- after = cur->next; +- io1 = container_of(after, ext4_io_end_t, list); +- +- ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n", +- io, inode->i_ino, io0, io1); +- } +- spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags); +-#endif +-} +- +-/* +- * This function is called from ext4_sync_file(). +- * +- * When IO is completed, the work to convert unwritten extents to +- * written is queued on workqueue but may not get immediately +- * scheduled. When fsync is called, we need to ensure the +- * conversion is complete before fsync returns. +- * The inode keeps track of a list of pending/completed IO that +- * might needs to do the conversion. This function walks through +- * the list and convert the related unwritten extents for completed IO +- * to written. +- * The function return the number of pending IOs on success. +- */ +-int ext4_flush_completed_IO(struct inode *inode) +-{ +- ext4_io_end_t *io; +- struct ext4_inode_info *ei = EXT4_I(inode); +- unsigned long flags; +- int ret = 0; +- int ret2 = 0; +- +- dump_completed_IO(inode); +- spin_lock_irqsave(&ei->i_completed_io_lock, flags); +- while (!list_empty(&ei->i_completed_io_list)){ +- io = list_entry(ei->i_completed_io_list.next, +- ext4_io_end_t, list); +- list_del_init(&io->list); +- io->flag |= EXT4_IO_END_IN_FSYNC; +- /* +- * Calling ext4_end_io_nolock() to convert completed +- * IO to written. +- * +- * When ext4_sync_file() is called, run_queue() may already +- * about to flush the work corresponding to this io structure. +- * It will be upset if it founds the io structure related +- * to the work-to-be schedule is freed. +- * +- * Thus we need to keep the io structure still valid here after +- * conversion finished. The io structure has a flag to +- * avoid double converting from both fsync and background work +- * queue work. +- */ +- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); +- ret = ext4_end_io_nolock(io); +- if (ret < 0) +- ret2 = ret; +- spin_lock_irqsave(&ei->i_completed_io_lock, flags); +- io->flag &= ~EXT4_IO_END_IN_FSYNC; +- } +- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); +- return (ret2 < 0) ? ret2 : 0; +-} +- + /* + * If we're not journaling and this is a just-created file, we have to + * sync our parent directory (if it was freshly created) since +diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c +index 830e1b2..61f13e5 100644 +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -807,11 +807,9 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, + + retry: + if (rw == READ && ext4_should_dioread_nolock(inode)) { +- if (unlikely(!list_empty(&ei->i_completed_io_list))) { +- mutex_lock(&inode->i_mutex); ++ if (unlikely(!list_empty(&ei->i_completed_io_list))) + ext4_flush_completed_IO(inode); +- mutex_unlock(&inode->i_mutex); +- } ++ + ret = __blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index acadd2b..dd3fd23 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2879,9 +2879,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, + { + struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; + ext4_io_end_t *io_end = iocb->private; +- struct workqueue_struct *wq; +- unsigned long flags; +- struct ext4_inode_info *ei; + + /* if not async direct IO or dio with 0 bytes write, just return */ + if (!io_end || !size) +@@ -2910,24 +2907,14 @@ out: + io_end->iocb = iocb; + io_end->result = ret; + } +- wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; +- +- /* Add the io_end to per-inode completed aio dio list*/ +- ei = EXT4_I(io_end->inode); +- spin_lock_irqsave(&ei->i_completed_io_lock, flags); +- list_add_tail(&io_end->list, &ei->i_completed_io_list); +- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); + +- /* queue the work to convert unwritten extents to written */ +- queue_work(wq, &io_end->work); ++ ext4_add_complete_io(io_end); + } + + static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) + { + ext4_io_end_t *io_end = bh->b_private; +- struct workqueue_struct *wq; + struct inode *inode; +- unsigned long flags; + + if (!test_clear_buffer_uninit(bh) || !io_end) + goto out; +@@ -2946,15 +2933,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) + */ + inode = io_end->inode; + ext4_set_io_unwritten_flag(inode, io_end); +- +- /* Add the io_end to per-inode completed io list*/ +- spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); +- list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list); +- spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags); +- +- wq = EXT4_SB(inode->i_sb)->dio_unwritten_wq; +- /* queue the work to convert unwritten extents to written */ +- queue_work(wq, &io_end->work); ++ ext4_add_complete_io(io_end); + out: + bh->b_private = NULL; + bh->b_end_io = NULL; +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 9970022..5b24c40 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -71,6 +71,7 @@ void ext4_free_io_end(ext4_io_end_t *io) + int i; + + BUG_ON(!io); ++ BUG_ON(!list_empty(&io->list)); + BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); + + if (io->page) +@@ -83,21 +84,14 @@ void ext4_free_io_end(ext4_io_end_t *io) + kmem_cache_free(io_end_cachep, io); + } + +-/* +- * check a range of space and convert unwritten extents to written. +- * +- * Called with inode->i_mutex; we depend on this when we manipulate +- * io->flag, since we could otherwise race with ext4_flush_completed_IO() +- */ +-int ext4_end_io_nolock(ext4_io_end_t *io) ++/* check a range of space and convert unwritten extents to written. */ ++static int ext4_end_io(ext4_io_end_t *io) + { + struct inode *inode = io->inode; + loff_t offset = io->offset; + ssize_t size = io->size; + int ret = 0; + +- BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN)); +- + ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p," + "list->prev 0x%p\n", + io, inode->i_ino, io->list.next, io->list.prev); +@@ -110,7 +104,6 @@ int ext4_end_io_nolock(ext4_io_end_t *io) + "(inode %lu, offset %llu, size %zd, error %d)", + inode->i_ino, offset, size, ret); + } +- io->flag &= ~EXT4_IO_END_UNWRITTEN; + if (io->iocb) + aio_complete(io->iocb, io->result, 0); + +@@ -122,51 +115,122 @@ int ext4_end_io_nolock(ext4_io_end_t *io) + return ret; + } + +-/* +- * work on completed aio dio IO, to convert unwritten extents to extents +- */ +-static void ext4_end_io_work(struct work_struct *work) ++static void dump_completed_IO(struct inode *inode) ++{ ++#ifdef EXT4FS_DEBUG ++ struct list_head *cur, *before, *after; ++ ext4_io_end_t *io, *io0, *io1; ++ unsigned long flags; ++ ++ if (list_empty(&EXT4_I(inode)->i_completed_io_list)) { ++ ext4_debug("inode %lu completed_io list is empty\n", ++ inode->i_ino); ++ return; ++ } ++ ++ ext4_debug("Dump inode %lu completed_io list\n", inode->i_ino); ++ list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list) { ++ cur = &io->list; ++ before = cur->prev; ++ io0 = container_of(before, ext4_io_end_t, list); ++ after = cur->next; ++ io1 = container_of(after, ext4_io_end_t, list); ++ ++ ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n", ++ io, inode->i_ino, io0, io1); ++ } ++#endif ++} ++ ++/* Add the io_end to per-inode completed end_io list. */ ++void ext4_add_complete_io(ext4_io_end_t *io_end) + { +- ext4_io_end_t *io = container_of(work, ext4_io_end_t, work); +- struct inode *inode = io->inode; +- struct ext4_inode_info *ei = EXT4_I(inode); +- unsigned long flags; ++ struct ext4_inode_info *ei = EXT4_I(io_end->inode); ++ struct workqueue_struct *wq; ++ unsigned long flags; ++ ++ BUG_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); ++ wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; + + spin_lock_irqsave(&ei->i_completed_io_lock, flags); +- if (io->flag & EXT4_IO_END_IN_FSYNC) +- goto requeue; +- if (list_empty(&io->list)) { +- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); +- goto free; ++ if (list_empty(&ei->i_completed_io_list)) { ++ io_end->flag |= EXT4_IO_END_QUEUED; ++ queue_work(wq, &io_end->work); + } ++ list_add_tail(&io_end->list, &ei->i_completed_io_list); ++ spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); ++} + +- if (!mutex_trylock(&inode->i_mutex)) { +- bool was_queued; +-requeue: +- was_queued = !!(io->flag & EXT4_IO_END_QUEUED); +- io->flag |= EXT4_IO_END_QUEUED; +- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); +- /* +- * Requeue the work instead of waiting so that the work +- * items queued after this can be processed. +- */ +- queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work); +- /* +- * To prevent the ext4-dio-unwritten thread from keeping +- * requeueing end_io requests and occupying cpu for too long, +- * yield the cpu if it sees an end_io request that has already +- * been requeued. +- */ +- if (was_queued) +- yield(); +- return; ++static int ext4_do_flush_completed_IO(struct inode *inode, ++ ext4_io_end_t *work_io) ++{ ++ ext4_io_end_t *io; ++ struct list_head unwritten, complete, to_free; ++ unsigned long flags; ++ struct ext4_inode_info *ei = EXT4_I(inode); ++ int err, ret = 0; ++ ++ INIT_LIST_HEAD(&complete); ++ INIT_LIST_HEAD(&to_free); ++ ++ spin_lock_irqsave(&ei->i_completed_io_lock, flags); ++ dump_completed_IO(inode); ++ list_replace_init(&ei->i_completed_io_list, &unwritten); ++ spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); ++ ++ while (!list_empty(&unwritten)) { ++ io = list_entry(unwritten.next, ext4_io_end_t, list); ++ BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN)); ++ list_del_init(&io->list); ++ ++ err = ext4_end_io(io); ++ if (unlikely(!ret && err)) ++ ret = err; ++ ++ list_add_tail(&io->list, &complete); ++ } ++ /* It is important to update all flags for all end_io in one shot w/o ++ * dropping the lock.*/ ++ spin_lock_irqsave(&ei->i_completed_io_lock, flags); ++ while (!list_empty(&complete)) { ++ io = list_entry(complete.next, ext4_io_end_t, list); ++ io->flag &= ~EXT4_IO_END_UNWRITTEN; ++ /* end_io context can not be destroyed now because it still ++ * used by queued worker. Worker thread will destroy it later */ ++ if (io->flag & EXT4_IO_END_QUEUED) ++ list_del_init(&io->list); ++ else ++ list_move(&io->list, &to_free); ++ } ++ /* If we are called from worker context, it is time to clear queued ++ * flag, and destroy it's end_io if it was converted already */ ++ if (work_io) { ++ work_io->flag &= ~EXT4_IO_END_QUEUED; ++ if (!(work_io->flag & EXT4_IO_END_UNWRITTEN)) ++ list_add_tail(&work_io->list, &to_free); + } +- list_del_init(&io->list); + spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); +- (void) ext4_end_io_nolock(io); +- mutex_unlock(&inode->i_mutex); +-free: +- ext4_free_io_end(io); ++ ++ while (!list_empty(&to_free)) { ++ io = list_entry(to_free.next, ext4_io_end_t, list); ++ list_del_init(&io->list); ++ ext4_free_io_end(io); ++ } ++ return ret; ++} ++ ++/* ++ * work on completed aio dio IO, to convert unwritten extents to extents ++ */ ++static void ext4_end_io_work(struct work_struct *work) ++{ ++ ext4_io_end_t *io = container_of(work, ext4_io_end_t, work); ++ ext4_do_flush_completed_IO(io->inode, io); ++} ++ ++int ext4_flush_completed_IO(struct inode *inode) ++{ ++ return ext4_do_flush_completed_IO(inode, NULL); + } + + ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) +@@ -199,9 +263,7 @@ static void buffer_io_error(struct buffer_head *bh) + static void ext4_end_bio(struct bio *bio, int error) + { + ext4_io_end_t *io_end = bio->bi_private; +- struct workqueue_struct *wq; + struct inode *inode; +- unsigned long flags; + int i; + sector_t bi_sector = bio->bi_sector; + +@@ -259,14 +321,7 @@ static void ext4_end_bio(struct bio *bio, int error) + return; + } + +- /* Add the io_end to per-inode completed io list*/ +- spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); +- list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list); +- spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags); +- +- wq = EXT4_SB(inode->i_sb)->dio_unwritten_wq; +- /* queue the work to convert unwritten extents to written */ +- queue_work(wq, &io_end->work); ++ ext4_add_complete_io(io_end); + } + + void ext4_io_submit(struct ext4_io_submit *io) +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0005-ext4-serialize-dio-nonlocked-reads-with-defrag-worke.patch b/0005-ext4-serialize-dio-nonlocked-reads-with-defrag-worke.patch new file mode 100644 index 000000000..cf53b8dab --- /dev/null +++ b/0005-ext4-serialize-dio-nonlocked-reads-with-defrag-worke.patch @@ -0,0 +1,144 @@ +From 994f567b2e99c82913a279ff438269c771b68a4b Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sat, 29 Sep 2012 00:41:21 -0400 +Subject: [PATCH 05/13] ext4: serialize dio nonlocked reads with defrag + workers + +Inode's block defrag and ext4_change_inode_journal_flag() may +affect nonlocked DIO reads result, so proper synchronization +required. + +- Add missed inode_dio_wait() calls where appropriate +- Check inode state under extra i_dio_count reference. + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 17335dcc471199717839b2fa3492ca36f70f1168) + +Conflicts: + fs/ext4/move_extent.c +--- + fs/ext4/ext4.h | 17 +++++++++++++++++ + fs/ext4/indirect.c | 14 ++++++++++++++ + fs/ext4/inode.c | 5 +++++ + fs/ext4/move_extent.c | 8 ++++++++ + 4 files changed, 44 insertions(+) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 7687d15..3e740e9 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1352,6 +1352,8 @@ enum { + EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/ + EXT4_STATE_NEWENTRY, /* File just added to dir */ + EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */ ++ EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read ++ nolocking */ + }; + + #define EXT4_INODE_BIT_FNS(name, field, offset) \ +@@ -2459,6 +2461,21 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh) + set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state); + } + ++/* ++ * Disable DIO read nolock optimization, so new dioreaders will be forced ++ * to grab i_mutex ++ */ ++static inline void ext4_inode_block_unlocked_dio(struct inode *inode) ++{ ++ ext4_set_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); ++ smp_mb(); ++} ++static inline void ext4_inode_resume_unlocked_dio(struct inode *inode) ++{ ++ smp_mb(); ++ ext4_clear_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); ++} ++ + #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + + /* For ioend & aio unwritten conversion wait queues */ +diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c +index 61f13e5..8d849da 100644 +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -810,11 +810,25 @@ retry: + if (unlikely(!list_empty(&ei->i_completed_io_list))) + ext4_flush_completed_IO(inode); + ++ /* ++ * Nolock dioread optimization may be dynamically disabled ++ * via ext4_inode_block_unlocked_dio(). Check inode's state ++ * while holding extra i_dio_count ref. ++ */ ++ atomic_inc(&inode->i_dio_count); ++ smp_mb(); ++ if (unlikely(ext4_test_inode_state(inode, ++ EXT4_STATE_DIOREAD_LOCK))) { ++ inode_dio_done(inode); ++ goto locked; ++ } + ret = __blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext4_get_block, NULL, NULL, 0); ++ inode_dio_done(inode); + } else { ++locked: + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, ext4_get_block); + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index dd3fd23..2bd7526 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4706,6 +4706,10 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) + return err; + } + ++ /* Wait for all existing dio workers */ ++ ext4_inode_block_unlocked_dio(inode); ++ inode_dio_wait(inode); ++ + jbd2_journal_lock_updates(journal); + + /* +@@ -4725,6 +4729,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) + ext4_set_aops(inode); + + jbd2_journal_unlock_updates(journal); ++ ext4_inode_resume_unlocked_dio(inode); + + /* Finally we can mark the inode as dirty. */ + +diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c +index c5826c6..fd1e32e 100644 +--- a/fs/ext4/move_extent.c ++++ b/fs/ext4/move_extent.c +@@ -1214,6 +1214,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, + /* Protect orig and donor inodes against a truncate */ + mext_inode_double_lock(orig_inode, donor_inode); + ++ /* Wait for all existing dio workers */ ++ ext4_inode_block_unlocked_dio(orig_inode); ++ ext4_inode_block_unlocked_dio(donor_inode); ++ inode_dio_wait(orig_inode); ++ inode_dio_wait(donor_inode); ++ + /* Protect extent tree against block allocations via delalloc */ + double_down_write_data_sem(orig_inode, donor_inode); + /* Check the filesystem environment whether move_extent can be done */ +@@ -1413,6 +1419,8 @@ out: + kfree(holecheck_path); + } + double_up_write_data_sem(orig_inode, donor_inode); ++ ext4_inode_resume_unlocked_dio(orig_inode); ++ ext4_inode_resume_unlocked_dio(donor_inode); + mext_inode_double_unlock(orig_inode, donor_inode); + + return ret; +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0006-ext4-serialize-unlocked-dio-reads-with-truncate.patch b/0006-ext4-serialize-unlocked-dio-reads-with-truncate.patch new file mode 100644 index 000000000..bddcc6024 --- /dev/null +++ b/0006-ext4-serialize-unlocked-dio-reads-with-truncate.patch @@ -0,0 +1,65 @@ +From 4c4679fc02744ec3955e88faf5e8b6844fa8cbd3 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sat, 29 Sep 2012 00:55:23 -0400 +Subject: [PATCH 06/13] ext4: serialize unlocked dio reads with truncate + +Current serialization will works only for DIO which holds +i_mutex, but nonlocked DIO following race is possible: + +dio_nolock_read_task truncate_task + ->ext4_setattr() + ->inode_dio_wait() +->ext4_ext_direct_IO + ->ext4_ind_direct_IO + ->__blockdev_direct_IO + ->ext4_get_block + ->truncate_setsize() + ->ext4_truncate() + #alloc truncated blocks + #to other inode + ->submit_io() + #INFORMATION LEAK + +In order to serialize with unlocked DIO reads we have to +rearrange wait sequence +1) update i_size first +2) if i_size about to be reduced wait for outstanding DIO requests +3) and only after that truncate inode blocks + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 1c9114f9c0f10f58dd7e568a7152025af47b27e5) +--- + fs/ext4/inode.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 2bd7526..b84322d 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4277,7 +4277,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) + } + + if (attr->ia_valid & ATTR_SIZE) { +- inode_dio_wait(inode); + + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); +@@ -4326,8 +4325,12 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) + } + + if (attr->ia_valid & ATTR_SIZE) { +- if (attr->ia_size != i_size_read(inode)) ++ if (attr->ia_size != i_size_read(inode)) { + truncate_setsize(inode, attr->ia_size); ++ /* Inode size will be reduced, wait for dio in flight */ ++ if (orphan) ++ inode_dio_wait(inode); ++ } + ext4_truncate(inode); + } + +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0007-ext4-endless-truncate-due-to-nonlocked-dio-readers.patch b/0007-ext4-endless-truncate-due-to-nonlocked-dio-readers.patch new file mode 100644 index 000000000..768215f48 --- /dev/null +++ b/0007-ext4-endless-truncate-due-to-nonlocked-dio-readers.patch @@ -0,0 +1,41 @@ +From ab7b8a329e12369d58e5fa59ba2e2c90370f12ef Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sat, 29 Sep 2012 00:56:15 -0400 +Subject: [PATCH 07/13] ext4: endless truncate due to nonlocked dio readers + +If we have enough aggressive DIO readers, truncate and other dio +waiters will wait forever inside inode_dio_wait(). It is reasonable +to disable nonlock DIO read optimization during truncate. + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 1b65007e9870e0021397b548e8cd6bbc584f9152) +--- + fs/ext4/inode.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index b84322d..3b03dd6 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4327,9 +4327,14 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) + if (attr->ia_valid & ATTR_SIZE) { + if (attr->ia_size != i_size_read(inode)) { + truncate_setsize(inode, attr->ia_size); +- /* Inode size will be reduced, wait for dio in flight */ +- if (orphan) ++ /* Inode size will be reduced, wait for dio in flight. ++ * Temporarily disable dioread_nolock to prevent ++ * livelock. */ ++ if (orphan) { ++ ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); ++ ext4_inode_resume_unlocked_dio(inode); ++ } + } + ext4_truncate(inode); + } +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0008-ext4-serialize-truncate-with-owerwrite-DIO-workers.patch b/0008-ext4-serialize-truncate-with-owerwrite-DIO-workers.patch new file mode 100644 index 000000000..c7733ed74 --- /dev/null +++ b/0008-ext4-serialize-truncate-with-owerwrite-DIO-workers.patch @@ -0,0 +1,61 @@ +From 69e4026a2d104ffcf1b935bc889f8abcbfbb29ec Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sat, 29 Sep 2012 00:58:26 -0400 +Subject: [PATCH 08/13] ext4: serialize truncate with owerwrite DIO workers + +Jan Kara have spotted interesting issue: +There are potential data corruption issue with direct IO overwrites +racing with truncate: + Like: + dio write truncate_task + ->ext4_ext_direct_IO + ->overwrite == 1 + ->down_read(&EXT4_I(inode)->i_data_sem); + ->mutex_unlock(&inode->i_mutex); + ->ext4_setattr() + ->inode_dio_wait() + ->truncate_setsize() + ->ext4_truncate() + ->down_write(&EXT4_I(inode)->i_data_sem); + ->__blockdev_direct_IO + ->ext4_get_block + ->submit_io() + ->up_read(&EXT4_I(inode)->i_data_sem); + # truncate data blocks, allocate them to + # other inode - bad stuff happens because + # dio is still in flight. + +In order to serialize with truncate dio worker should grab extra i_dio_count +reference before drop i_mutex. + +Reviewed-by: Jan Kara +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 1f555cfa29e8f787d675e8390f88ce517a37271a) +--- + fs/ext4/inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 3b03dd6..484a327 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3008,6 +3008,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, + overwrite = *((int *)iocb->private); + + if (overwrite) { ++ atomic_inc(&inode->i_dio_count); + down_read(&EXT4_I(inode)->i_data_sem); + mutex_unlock(&inode->i_mutex); + } +@@ -3105,6 +3106,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, + retake_lock: + /* take i_mutex locking again if we do a ovewrite dio */ + if (overwrite) { ++ inode_dio_done(inode); + up_read(&EXT4_I(inode)->i_data_sem); + mutex_lock(&inode->i_mutex); + } +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0009-ext4-punch_hole-should-wait-for-DIO-writers.patch b/0009-ext4-punch_hole-should-wait-for-DIO-writers.patch new file mode 100644 index 000000000..4d7636668 --- /dev/null +++ b/0009-ext4-punch_hole-should-wait-for-DIO-writers.patch @@ -0,0 +1,125 @@ +From 71a6398a4b59ddcf920dfb68872b5a771c606e3a Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sun, 30 Sep 2012 23:03:42 -0400 +Subject: [PATCH 09/13] ext4: punch_hole should wait for DIO writers + +punch_hole is the place where we have to wait for all existing writers +(writeback, aio, dio), but currently we simply flush pended end_io request +which is not sufficient. Other issue is that punch_hole performed w/o i_mutex +held which obviously result in dangerous data corruption due to +write-after-free. + +This patch performs following changes: +- Guard punch_hole with i_mutex +- Recheck inode flags under i_mutex +- Block all new dio readers in order to prevent information leak caused by + read-after-free pattern. +- punch_hole now wait for all writers in flight + NOTE: XXX write-after-free race is still possible because new dirty pages + may appear due to mmap(), and currently there is no easy way to stop + writeback while punch_hole is in progress. + +[ Fixed error return from ext4_ext_punch_hole() to make sure that we + release i_mutex before returning EPERM or ETXTBUSY -- Ted ] + +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 02d262dffcf4c74e5c4612ee736bdb94f18ed5b9) +--- + fs/ext4/extents.c | 53 ++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 36 insertions(+), 17 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 1fbf2ff..202eb4d 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4776,9 +4776,32 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) + loff_t first_page_offset, last_page_offset; + int credits, err = 0; + ++ /* ++ * Write out all dirty pages to avoid race conditions ++ * Then release them. ++ */ ++ if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { ++ err = filemap_write_and_wait_range(mapping, ++ offset, offset + length - 1); ++ ++ if (err) ++ return err; ++ } ++ ++ mutex_lock(&inode->i_mutex); ++ /* It's not possible punch hole on append only file */ ++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { ++ err = -EPERM; ++ goto out_mutex; ++ } ++ if (IS_SWAPFILE(inode)) { ++ err = -ETXTBSY; ++ goto out_mutex; ++ } ++ + /* No need to punch hole beyond i_size */ + if (offset >= inode->i_size) +- return 0; ++ goto out_mutex; + + /* + * If the hole extends beyond i_size, set the hole +@@ -4796,33 +4819,25 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) + first_page_offset = first_page << PAGE_CACHE_SHIFT; + last_page_offset = last_page << PAGE_CACHE_SHIFT; + +- /* +- * Write out all dirty pages to avoid race conditions +- * Then release them. +- */ +- if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { +- err = filemap_write_and_wait_range(mapping, +- offset, offset + length - 1); +- +- if (err) +- return err; +- } +- + /* Now release the pages */ + if (last_page_offset > first_page_offset) { + truncate_pagecache_range(inode, first_page_offset, + last_page_offset - 1); + } + +- /* finish any pending end_io work */ ++ /* Wait all existing dio workers, newcomers will block on i_mutex */ ++ ext4_inode_block_unlocked_dio(inode); ++ inode_dio_wait(inode); + err = ext4_flush_completed_IO(inode); + if (err) +- return err; ++ goto out_dio; + + credits = ext4_writepage_trans_blocks(inode); + handle = ext4_journal_start(inode, credits); +- if (IS_ERR(handle)) +- return PTR_ERR(handle); ++ if (IS_ERR(handle)) { ++ err = PTR_ERR(handle); ++ goto out_dio; ++ } + + err = ext4_orphan_add(handle, inode); + if (err) +@@ -4916,6 +4931,10 @@ out: + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + ext4_mark_inode_dirty(handle, inode); + ext4_journal_stop(handle); ++out_dio: ++ ext4_inode_resume_unlocked_dio(inode); ++out_mutex: ++ mutex_unlock(&inode->i_mutex); + return err; + } + int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0010-ext4-fix-ext_remove_space-for-punch_hole-case.patch b/0010-ext4-fix-ext_remove_space-for-punch_hole-case.patch new file mode 100644 index 000000000..d161bb765 --- /dev/null +++ b/0010-ext4-fix-ext_remove_space-for-punch_hole-case.patch @@ -0,0 +1,60 @@ +From 66d08dd92b82dabfd64853aa4edde1547fdf9ef7 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Sun, 30 Sep 2012 23:03:50 -0400 +Subject: [PATCH 10/13] ext4: fix ext_remove_space for punch_hole case + +Inode is allowed to have empty leaf only if it this is blockless inode. + +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 6f2080e64487b9963f9c6ff8a252e1abce98f2d4) +--- + fs/ext4/extents.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 202eb4d..b1c92c0 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -2572,7 +2572,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + struct ext4_ext_path *path = NULL; + ext4_fsblk_t partial_cluster = 0; + handle_t *handle; +- int i = 0, err; ++ int i = 0, err = 0; + + ext_debug("truncate since %u to %u\n", start, end); + +@@ -2604,12 +2604,16 @@ again: + return PTR_ERR(path); + } + depth = ext_depth(inode); ++ /* Leaf not may not exist only if inode has no blocks at all */ + ex = path[depth].p_ext; + if (!ex) { +- ext4_ext_drop_refs(path); +- kfree(path); +- path = NULL; +- goto cont; ++ if (depth) { ++ EXT4_ERROR_INODE(inode, ++ "path[%d].p_hdr == NULL", ++ depth); ++ err = -EIO; ++ } ++ goto out; + } + + ee_block = le32_to_cpu(ex->ee_block); +@@ -2641,8 +2645,6 @@ again: + goto out; + } + } +-cont: +- + /* + * We start scanning from right side, freeing all the blocks + * after i_size and walking into the tree depth-wise. +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0011-ext4-fix-ext4_flush_completed_IO-wait-semantics.patch b/0011-ext4-fix-ext4_flush_completed_IO-wait-semantics.patch new file mode 100644 index 000000000..517b20129 --- /dev/null +++ b/0011-ext4-fix-ext4_flush_completed_IO-wait-semantics.patch @@ -0,0 +1,176 @@ +From ca6d3910cbf8854f3f3b9846391f669733899101 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 5 Oct 2012 11:31:55 -0400 +Subject: [PATCH 11/13] ext4: fix ext4_flush_completed_IO wait semantics + +BUG #1) All places where we call ext4_flush_completed_IO are broken + because buffered io and DIO/AIO goes through three stages + 1) submitted io, + 2) completed io (in i_completed_io_list) conversion pended + 3) finished io (conversion done) + And by calling ext4_flush_completed_IO we will flush only + requests which were in (2) stage, which is wrong because: + 1) punch_hole and truncate _must_ wait for all outstanding unwritten io + regardless to it's state. + 2) fsync and nolock_dio_read should also wait because there is + a time window between end_page_writeback() and ext4_add_complete_io() + As result integrity fsync is broken in case of buffered write + to fallocated region: + fsync blkdev_completion + ->filemap_write_and_wait_range + ->ext4_end_bio + ->end_page_writeback + <-- filemap_write_and_wait_range return + ->ext4_flush_completed_IO + sees empty i_completed_io_list but pended + conversion still exist + ->ext4_add_complete_io + +BUG #2) Race window becomes wider due to the 'ext4: completed_io +locking cleanup V4' patch series + +This patch make following changes: +1) ext4_flush_completed_io() now first try to flush completed io and when + wait for any outstanding unwritten io via ext4_unwritten_wait() +2) Rename function to more appropriate name. +3) Assert that all callers of ext4_flush_unwritten_io should hold i_mutex to + prevent endless wait + +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +Reviewed-by: Jan Kara +(cherry picked from commit c278531d39f3158bfee93dc67da0b77e09776de2) +--- + fs/ext4/ext4.h | 3 ++- + fs/ext4/extents.c | 6 +++--- + fs/ext4/file.c | 2 +- + fs/ext4/fsync.c | 2 +- + fs/ext4/indirect.c | 8 +++++--- + fs/ext4/page-io.c | 11 +++++++---- + 6 files changed, 19 insertions(+), 13 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 3e740e9..7f13292 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1941,7 +1941,7 @@ extern void ext4_htree_free_dir_info(struct dir_private_info *p); + + /* fsync.c */ + extern int ext4_sync_file(struct file *, loff_t, loff_t, int); +-extern int ext4_flush_completed_IO(struct inode *); ++extern int ext4_flush_unwritten_io(struct inode *); + + /* hash.c */ + extern int ext4fs_dirhash(const char *name, int len, struct +@@ -2361,6 +2361,7 @@ extern const struct file_operations ext4_dir_operations; + extern const struct inode_operations ext4_file_inode_operations; + extern const struct file_operations ext4_file_operations; + extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); ++extern void ext4_unwritten_wait(struct inode *inode); + + /* namei.c */ + extern const struct inode_operations ext4_dir_inode_operations; +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index b1c92c0..37f46eb 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4250,7 +4250,7 @@ void ext4_ext_truncate(struct inode *inode) + * finish any pending end_io work so we won't run the risk of + * converting any truncated blocks to initialized later + */ +- ext4_flush_completed_IO(inode); ++ ext4_flush_unwritten_io(inode); + + /* + * probably first extent we're gonna free will be last in block +@@ -4829,10 +4829,10 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) + + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); +- inode_dio_wait(inode); +- err = ext4_flush_completed_IO(inode); ++ err = ext4_flush_unwritten_io(inode); + if (err) + goto out_dio; ++ inode_dio_wait(inode); + + credits = ext4_writepage_trans_blocks(inode); + handle = ext4_journal_start(inode, credits); +diff --git a/fs/ext4/file.c b/fs/ext4/file.c +index 39335bd..ca6f07a 100644 +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -55,7 +55,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp) + return 0; + } + +-static void ext4_unwritten_wait(struct inode *inode) ++void ext4_unwritten_wait(struct inode *inode) + { + wait_queue_head_t *wq = ext4_ioend_wq(inode); + +diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c +index 520b058..76051c6 100644 +--- a/fs/ext4/fsync.c ++++ b/fs/ext4/fsync.c +@@ -138,7 +138,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) + if (inode->i_sb->s_flags & MS_RDONLY) + goto out; + +- ret = ext4_flush_completed_IO(inode); ++ ret = ext4_flush_unwritten_io(inode); + if (ret < 0) + goto out; + +diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c +index 8d849da..792e388 100644 +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -807,9 +807,11 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, + + retry: + if (rw == READ && ext4_should_dioread_nolock(inode)) { +- if (unlikely(!list_empty(&ei->i_completed_io_list))) +- ext4_flush_completed_IO(inode); +- ++ if (unlikely(atomic_read(&EXT4_I(inode)->i_unwritten))) { ++ mutex_lock(&inode->i_mutex); ++ ext4_flush_unwritten_io(inode); ++ mutex_unlock(&inode->i_mutex); ++ } + /* + * Nolock dioread optimization may be dynamically disabled + * via ext4_inode_block_unlocked_dio(). Check inode's state +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 5b24c40..68e896e 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -189,8 +189,6 @@ static int ext4_do_flush_completed_IO(struct inode *inode, + + list_add_tail(&io->list, &complete); + } +- /* It is important to update all flags for all end_io in one shot w/o +- * dropping the lock.*/ + spin_lock_irqsave(&ei->i_completed_io_lock, flags); + while (!list_empty(&complete)) { + io = list_entry(complete.next, ext4_io_end_t, list); +@@ -228,9 +226,14 @@ static void ext4_end_io_work(struct work_struct *work) + ext4_do_flush_completed_IO(io->inode, io); + } + +-int ext4_flush_completed_IO(struct inode *inode) ++int ext4_flush_unwritten_io(struct inode *inode) + { +- return ext4_do_flush_completed_IO(inode, NULL); ++ int ret; ++ WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) && ++ !(inode->i_state & I_FREEING)); ++ ret = ext4_do_flush_completed_IO(inode, NULL); ++ ext4_unwritten_wait(inode); ++ return ret; + } + + ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0012-ext4-serialize-fallocate-with-ext4_convert_unwritten.patch b/0012-ext4-serialize-fallocate-with-ext4_convert_unwritten.patch new file mode 100644 index 000000000..3fcaef1f2 --- /dev/null +++ b/0012-ext4-serialize-fallocate-with-ext4_convert_unwritten.patch @@ -0,0 +1,46 @@ +From 9f00d109efeaf4d12d56c8e46cd13af80e344f97 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 5 Oct 2012 11:32:02 -0400 +Subject: [PATCH 12/13] ext4: serialize fallocate with + ext4_convert_unwritten_extents + +Fallocate should wait for pended ext4_convert_unwritten_extents() +otherwise following race may happen: + +ftruncate( ,12288); +fallocate( ,0, 4096) +io_sibmit( ,0, 4096); /* Write to fallocated area, split extent if needed */ +fallocate( ,0, 8192); /* Grow extent and broke assumption about extent */ + +Later kwork completion will do: + ->ext4_convert_unwritten_extents (0, 4096) + ->ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_IO_CONVERT_EXT); + ->ext4_ext_map_blocks() /* Will find new extent: ex = [0,2] !!!!!! */ + ->ext4_ext_handle_uninitialized_extents() + ->ext4_convert_unwritten_extents_endio() + /* convert [0,2] extent to initialized, but only[0,1] was written */ + +Signed-off-by: Dmitry Monakhov +Signed-off-by: "Theodore Ts'o" +(cherry picked from commit 60d4616f3dc63371b3dc367e5e88fd4b4f037f65) +--- + fs/ext4/extents.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 37f46eb..ea2db86 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4410,6 +4410,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) + */ + if (len <= EXT_UNINIT_MAX_LEN << blkbits) + flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; ++ ++ /* Prevent race condition between unwritten */ ++ ext4_flush_unwritten_io(inode); + retry: + while (ret >= 0 && ret < max_blocks) { + map.m_lblk = map.m_lblk + ret; +-- +1.7.12.rc0.22.gcdd159b + diff --git a/0013-ext4-race-condition-protection-for-ext4_convert_unwr.patch b/0013-ext4-race-condition-protection-for-ext4_convert_unwr.patch new file mode 100644 index 000000000..ffd7975c6 --- /dev/null +++ b/0013-ext4-race-condition-protection-for-ext4_convert_unwr.patch @@ -0,0 +1,153 @@ +From 5ff6b4cc64765e10df509a60e902561efdeb58d5 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 5 Oct 2012 11:32:04 -0400 +Subject: [PATCH 13/13] ext4: race-condition protection for + ext4_convert_unwritten_extents_endio + +We assumed that at the time we call ext4_convert_unwritten_extents_endio() +extent in question is fully inside [map.m_lblk, map->m_len] because +it was already split during submission. But this may not be true due to +a race between writeback vs fallocate. + +If extent in question is larger than requested we will split it again. +Special precautions should being done if zeroout required because +[map.m_lblk, map->m_len] already contains valid data. + +Signed-off-by: Dmitry Monakhov +(cherry picked from commit 0d4b4ff5282d07a4f83b87b3117cd898b0a3f673) +--- + fs/ext4/extents.c | 57 ++++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 46 insertions(+), 11 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index ea2db86..ee0d61c 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -52,6 +52,9 @@ + #define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ + #define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ + ++#define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */ ++#define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */ ++ + static __le32 ext4_extent_block_csum(struct inode *inode, + struct ext4_extent_header *eh) + { +@@ -2897,6 +2900,9 @@ static int ext4_split_extent_at(handle_t *handle, + unsigned int ee_len, depth; + int err = 0; + ++ BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) == ++ (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)); ++ + ext_debug("ext4_split_extents_at: inode %lu, logical" + "block %llu\n", inode->i_ino, (unsigned long long)split); + +@@ -2955,7 +2961,14 @@ static int ext4_split_extent_at(handle_t *handle, + + err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); + if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { +- err = ext4_ext_zeroout(inode, &orig_ex); ++ if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { ++ if (split_flag & EXT4_EXT_DATA_VALID1) ++ err = ext4_ext_zeroout(inode, ex2); ++ else ++ err = ext4_ext_zeroout(inode, ex); ++ } else ++ err = ext4_ext_zeroout(inode, &orig_ex); ++ + if (err) + goto fix_extent_len; + /* update the extent length and mark as initialized */ +@@ -3008,12 +3021,13 @@ static int ext4_split_extent(handle_t *handle, + uninitialized = ext4_ext_is_uninitialized(ex); + + if (map->m_lblk + map->m_len < ee_block + ee_len) { +- split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ? +- EXT4_EXT_MAY_ZEROOUT : 0; ++ split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT; + flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; + if (uninitialized) + split_flag1 |= EXT4_EXT_MARK_UNINIT1 | + EXT4_EXT_MARK_UNINIT2; ++ if (split_flag & EXT4_EXT_DATA_VALID2) ++ split_flag1 |= EXT4_EXT_DATA_VALID1; + err = ext4_split_extent_at(handle, inode, path, + map->m_lblk + map->m_len, split_flag1, flags1); + if (err) +@@ -3026,8 +3040,8 @@ static int ext4_split_extent(handle_t *handle, + return PTR_ERR(path); + + if (map->m_lblk >= ee_block) { +- split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ? +- EXT4_EXT_MAY_ZEROOUT : 0; ++ split_flag1 = split_flag & (EXT4_EXT_MAY_ZEROOUT | ++ EXT4_EXT_DATA_VALID2); + if (uninitialized) + split_flag1 |= EXT4_EXT_MARK_UNINIT1; + if (split_flag & EXT4_EXT_MARK_UNINIT2) +@@ -3305,26 +3319,47 @@ static int ext4_split_unwritten_extents(handle_t *handle, + + split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; + split_flag |= EXT4_EXT_MARK_UNINIT2; +- ++ if (flags & EXT4_GET_BLOCKS_CONVERT) ++ split_flag |= EXT4_EXT_DATA_VALID2; + flags |= EXT4_GET_BLOCKS_PRE_IO; + return ext4_split_extent(handle, inode, path, map, split_flag, flags); + } + + static int ext4_convert_unwritten_extents_endio(handle_t *handle, +- struct inode *inode, +- struct ext4_ext_path *path) ++ struct inode *inode, ++ struct ext4_map_blocks *map, ++ struct ext4_ext_path *path) + { + struct ext4_extent *ex; ++ ext4_lblk_t ee_block; ++ unsigned int ee_len; + int depth; + int err = 0; + + depth = ext_depth(inode); + ex = path[depth].p_ext; ++ ee_block = le32_to_cpu(ex->ee_block); ++ ee_len = ext4_ext_get_actual_len(ex); + + ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical" + "block %llu, max_blocks %u\n", inode->i_ino, +- (unsigned long long)le32_to_cpu(ex->ee_block), +- ext4_ext_get_actual_len(ex)); ++ (unsigned long long)ee_block, ee_len); ++ ++ /* If extent is larger than requested then split is required */ ++ if (ee_block != map->m_lblk || ee_len > map->m_len) { ++ err = ext4_split_unwritten_extents(handle, inode, map, path, ++ EXT4_GET_BLOCKS_CONVERT); ++ if (err < 0) ++ goto out; ++ ext4_ext_drop_refs(path); ++ path = ext4_ext_find_extent(inode, map->m_lblk, path); ++ if (IS_ERR(path)) { ++ err = PTR_ERR(path); ++ goto out; ++ } ++ depth = ext_depth(inode); ++ ex = path[depth].p_ext; ++ } + + err = ext4_ext_get_access(handle, inode, path + depth); + if (err) +@@ -3634,7 +3669,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, + } + /* IO end_io complete, convert the filled extent to written */ + if ((flags & EXT4_GET_BLOCKS_CONVERT)) { +- ret = ext4_convert_unwritten_extents_endio(handle, inode, ++ ret = ext4_convert_unwritten_extents_endio(handle, inode, map, + path); + if (ret >= 0) { + ext4_update_inode_fsync_trans(handle, inode, 1); +-- +1.7.12.rc0.22.gcdd159b + diff --git a/8139cp-re-enable-interrupts-after-tx-timeout.patch b/8139cp-re-enable-interrupts-after-tx-timeout.patch new file mode 100644 index 000000000..c0196188e --- /dev/null +++ b/8139cp-re-enable-interrupts-after-tx-timeout.patch @@ -0,0 +1,29 @@ +From 01ffc0a7f1c1801a2354719dedbc32aff45b987d Mon Sep 17 00:00:00 2001 +From: David Woodhouse +Date: Sat, 24 Nov 2012 12:11:21 +0000 +Subject: [PATCH] 8139cp: re-enable interrupts after tx timeout + +Recovery doesn't work too well if we leave interrupts disabled... + +Signed-off-by: David Woodhouse +Acked-by: Francois Romieu +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/8139cp.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c +index 3de318d..6cb96b4 100644 +--- a/drivers/net/ethernet/realtek/8139cp.c ++++ b/drivers/net/ethernet/realtek/8139cp.c +@@ -1219,6 +1219,7 @@ static void cp_tx_timeout(struct net_device *dev) + cp_clean_rings(cp); + rc = cp_init_rings(cp); + cp_start_hw(cp); ++ cp_enable_irq(cp); + + netif_wake_queue(dev); + +-- +1.7.6.5 + diff --git a/8139cp-revert-set-ring-address-before-enabling-receiver.patch b/8139cp-revert-set-ring-address-before-enabling-receiver.patch new file mode 100644 index 000000000..07ae2c28d --- /dev/null +++ b/8139cp-revert-set-ring-address-before-enabling-receiver.patch @@ -0,0 +1,64 @@ +From b26623dab7eeb1e9f5898c7a49458789dd492f20 Mon Sep 17 00:00:00 2001 +From: Francois Romieu +Date: Wed, 21 Nov 2012 10:07:29 +0000 +Subject: 8139cp: revert "set ring address before enabling receiver" + +From: Francois Romieu + +commit b26623dab7eeb1e9f5898c7a49458789dd492f20 upstream. + +This patch reverts b01af4579ec41f48e9b9c774e70bd6474ad210db. + +The original patch was tested with emulated hardware. Real +hardware chokes. + +Fixes https://bugzilla.kernel.org/show_bug.cgi?id=47041 + +Signed-off-by: Francois Romieu +Acked-by: Jeff Garzik +Signed-off-by: David S. Miller +Signed-off-by: CAI Qian +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ethernet/realtek/8139cp.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/realtek/8139cp.c ++++ b/drivers/net/ethernet/realtek/8139cp.c +@@ -979,17 +979,6 @@ static void cp_init_hw (struct cp_privat + cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); + cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); + +- cpw32_f(HiTxRingAddr, 0); +- cpw32_f(HiTxRingAddr + 4, 0); +- +- ring_dma = cp->ring_dma; +- cpw32_f(RxRingAddr, ring_dma & 0xffffffff); +- cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); +- +- ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; +- cpw32_f(TxRingAddr, ring_dma & 0xffffffff); +- cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); +- + cp_start_hw(cp); + cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ + +@@ -1003,6 +992,17 @@ static void cp_init_hw (struct cp_privat + + cpw8(Config5, cpr8(Config5) & PMEStatus); + ++ cpw32_f(HiTxRingAddr, 0); ++ cpw32_f(HiTxRingAddr + 4, 0); ++ ++ ring_dma = cp->ring_dma; ++ cpw32_f(RxRingAddr, ring_dma & 0xffffffff); ++ cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); ++ ++ ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; ++ cpw32_f(TxRingAddr, ring_dma & 0xffffffff); ++ cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); ++ + cpw16(MultiIntr, 0); + + cpw8_f(Cfg9346, Cfg9346_Lock); diff --git a/8139cp-set-ring-address-after-enabling-C-mode.patch b/8139cp-set-ring-address-after-enabling-C-mode.patch new file mode 100644 index 000000000..33bd340e9 --- /dev/null +++ b/8139cp-set-ring-address-after-enabling-C-mode.patch @@ -0,0 +1,100 @@ +From a9dbe40fc10cea2efe6e1ff9e03c62dd7579c5ba Mon Sep 17 00:00:00 2001 +From: David Woodhouse +Date: Wed, 21 Nov 2012 10:27:19 +0000 +Subject: [PATCH] 8139cp: set ring address after enabling C+ mode + +This fixes (for me) a regression introduced by commit b01af457 ("8139cp: +set ring address before enabling receiver"). That commit configured the +descriptor ring addresses earlier in the initialisation sequence, in +order to avoid the possibility of triggering stray DMA before the +correct address had been set up. + +Unfortunately, it seems that the hardware will scribble garbage into the +TxRingAddr registers when we enable "plus mode" Tx in the CpCmd +register. Observed on a Traverse Geos router board. + +To deal with this, while not reintroducing the problem which led to the +original commit, we augment cp_start_hw() to write to the CpCmd register +*first*, then set the descriptor ring addresses, and then finally to +enable Rx and Tx in the original 8139 Cmd register. The datasheet +actually indicates that we should enable Tx/Rx in the Cmd register +*before* configuring the descriptor addresses, but that would appear to +re-introduce the problem that the offending commit b01af457 was trying +to solve. And this variant appears to work fine on real hardware. + +Signed-off-by: David Woodhouse +Cc: stable@kernel.org [3.5+] +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/8139cp.c | 40 +++++++++++++++++++++++---------- + 1 files changed, 28 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c +index 1c81825..5166d94 100644 +--- a/drivers/net/ethernet/realtek/8139cp.c ++++ b/drivers/net/ethernet/realtek/8139cp.c +@@ -957,7 +957,35 @@ static void cp_reset_hw (struct cp_private *cp) + + static inline void cp_start_hw (struct cp_private *cp) + { ++ dma_addr_t ring_dma; ++ + cpw16(CpCmd, cp->cpcmd); ++ ++ /* ++ * These (at least TxRingAddr) need to be configured after the ++ * corresponding bits in CpCmd are enabled. Datasheet v1.6 §6.33 ++ * (C+ Command Register) recommends that these and more be configured ++ * *after* the [RT]xEnable bits in CpCmd are set. And on some hardware ++ * it's been observed that the TxRingAddr is actually reset to garbage ++ * when C+ mode Tx is enabled in CpCmd. ++ */ ++ cpw32_f(HiTxRingAddr, 0); ++ cpw32_f(HiTxRingAddr + 4, 0); ++ ++ ring_dma = cp->ring_dma; ++ cpw32_f(RxRingAddr, ring_dma & 0xffffffff); ++ cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); ++ ++ ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; ++ cpw32_f(TxRingAddr, ring_dma & 0xffffffff); ++ cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); ++ ++ /* ++ * Strictly speaking, the datasheet says this should be enabled ++ * *before* setting the descriptor addresses. But what, then, would ++ * prevent it from doing DMA to random unconfigured addresses? ++ * This variant appears to work fine. ++ */ + cpw8(Cmd, RxOn | TxOn); + } + +@@ -969,7 +997,6 @@ static void cp_enable_irq(struct cp_private *cp) + static void cp_init_hw (struct cp_private *cp) + { + struct net_device *dev = cp->dev; +- dma_addr_t ring_dma; + + cp_reset_hw(cp); + +@@ -979,17 +1006,6 @@ static void cp_init_hw (struct cp_private *cp) + cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); + cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); + +- cpw32_f(HiTxRingAddr, 0); +- cpw32_f(HiTxRingAddr + 4, 0); +- +- ring_dma = cp->ring_dma; +- cpw32_f(RxRingAddr, ring_dma & 0xffffffff); +- cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); +- +- ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; +- cpw32_f(TxRingAddr, ring_dma & 0xffffffff); +- cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); +- + cp_start_hw(cp); + cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ + +-- +1.7.6.5 + diff --git a/ACPI-do-not-use-Lid-and-Sleep-button-for-S5-wakeup.patch b/ACPI-do-not-use-Lid-and-Sleep-button-for-S5-wakeup.patch new file mode 100644 index 000000000..f6e997c41 --- /dev/null +++ b/ACPI-do-not-use-Lid-and-Sleep-button-for-S5-wakeup.patch @@ -0,0 +1,46 @@ +From b7e383046c2c7c13ad928cd7407eafff758ddd4b Mon Sep 17 00:00:00 2001 +From: Zhang Rui +Date: Tue, 4 Dec 2012 23:23:16 +0100 +Subject: [PATCH] ACPI : do not use Lid and Sleep button for S5 wakeup + +When system enters power off, the _PSW of Lid device is enabled. +But this may cause the system to reboot instead of power off. + +A proper way to fix this is to always disable lid wakeup capability for S5. + +References: https://bugzilla.kernel.org/show_bug.cgi?id=35262 +Signed-off-by: Zhang Rui +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/scan.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index d0b38ab..bd523bf 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -917,8 +917,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, + static void acpi_bus_set_run_wake_flags(struct acpi_device *device) + { + struct acpi_device_id button_device_ids[] = { +- {"PNP0C0D", 0}, + {"PNP0C0C", 0}, ++ {"PNP0C0D", 0}, + {"PNP0C0E", 0}, + {"", 0}, + }; +@@ -930,6 +930,11 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) + /* Power button, Lid switch always enable wakeup */ + if (!acpi_match_device_ids(device, button_device_ids)) { + device->wakeup.flags.run_wake = 1; ++ if (!acpi_match_device_ids(device, &button_device_ids[1])) { ++ /* Do not use Lid/sleep button for S5 wakeup */ ++ if (device->wakeup.sleep_state == ACPI_STATE_S5) ++ device->wakeup.sleep_state = ACPI_STATE_S4; ++ } + device_set_wakeup_capable(&device->dev, true); + return; + } +-- +1.8.0.1 + diff --git a/Bluetooth-Add-support-for-BCM20702A0.patch b/Bluetooth-Add-support-for-BCM20702A0.patch new file mode 100644 index 000000000..73f00fc43 --- /dev/null +++ b/Bluetooth-Add-support-for-BCM20702A0.patch @@ -0,0 +1,107 @@ +From 7f198e1cc6d4fda9c84c0da4fc3aafb441342f78 Mon Sep 17 00:00:00 2001 +From: Jaroslav Resler +Date: Tue, 11 Sep 2012 17:25:32 +0800 +Subject: [PATCH 1/2] Bluetooth: Add support for BCM20702A0 [04ca, 2003] + +Add another vendor specific ID for BCM20702A0. + +output of usb-devices: +T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 +D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=04ca ProdID=2003 Rev= 1.12 +S: Manufacturer=Broadcom Corp +S: Product=BCM20702A0 +S: SerialNumber=446D57861623 +C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA +I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms +E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) +E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms +E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms +I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) + +Signed-off-by: Cho, Yu-Chen +Signed-off-by: Gustavo Padovan +--- + drivers/bluetooth/btusb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 654e248..b167944 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = { + { USB_DEVICE(0x0c10, 0x0000) }, + + /* Broadcom BCM20702A0 */ ++ { USB_DEVICE(0x04ca, 0x2003) }, + { USB_DEVICE(0x0489, 0xe042) }, + { USB_DEVICE(0x413c, 0x8197) }, + +-- +1.8.0 + + +From a5f86c3423428c8e28b6501d0e9c3929ca91f07d Mon Sep 17 00:00:00 2001 +From: Jeff Cook +Date: Fri, 9 Nov 2012 16:39:48 -0700 +Subject: [PATCH 2/2] Bluetooth: Add support for BCM20702A0 [0b05, 17b5] + +Vendor-specific ID for BCM20702A0. +Support for bluetooth over Asus Wi-Fi GO!, included with Asus P8Z77-V +Deluxe. + +T: Bus=07 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 +D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0b05 ProdID=17b5 Rev=01.12 +S: Manufacturer=Broadcom Corp +S: Product=BCM20702A0 +S: SerialNumber=94DBC98AC113 +C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) +I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) +I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) +I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) + +Cc: stable@vger.kernel.org +Signed-off-by: Jeff Cook +Signed-off-by: Gustavo Padovan +--- + drivers/bluetooth/btusb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index b167944..6dc44ff 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = { + { USB_DEVICE(0x0c10, 0x0000) }, + + /* Broadcom BCM20702A0 */ ++ { USB_DEVICE(0x0b05, 0x17b5) }, + { USB_DEVICE(0x04ca, 0x2003) }, + { USB_DEVICE(0x0489, 0xe042) }, + { USB_DEVICE(0x413c, 0x8197) }, +-- +1.8.0 + diff --git a/Makefile b/Makefile index 0b7442ab7..5b7b72450 100644 --- a/Makefile +++ b/Makefile @@ -17,15 +17,16 @@ help: include Makefile.config -ifndef KVERSION -KVERSION := $(shell awk '$$1 == "%define" && $$2 == "base_sublevel" { \ - print "2.6." $$3 \ - }' $(SPECFILE)) -endif - prep: fedpkg -v prep --arch=$(PREPARCH) +noarch: + fedpkg -v local --arch=noarch + +# 'make local' also needs to build the noarch firmware package +local: noarch + fedpkg -v local + extremedebug: @perl -pi -e 's/# CONFIG_DEBUG_PAGEALLOC is not set/CONFIG_DEBUG_PAGEALLOC=y/' config-nodebug @@ -36,18 +37,17 @@ debug: @perl -pi -e 's/# CONFIG_DEBUG_SLAB is not set/CONFIG_DEBUG_SLAB=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_MUTEXES is not set/CONFIG_DEBUG_MUTEXES=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_RT_MUTEXES is not set/CONFIG_DEBUG_RT_MUTEXES=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_RWSEMS is not set/CONFIG_DEBUG_RWSEMS=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_LOCK_ALLOC is not set/CONFIG_DEBUG_LOCK_ALLOC=y/' config-nodebug @perl -pi -e 's/# CONFIG_PROVE_LOCKING is not set/CONFIG_PROVE_LOCKING=y/' config-nodebug @perl -pi -e 's/# CONFIG_PROVE_RCU is not set/CONFIG_PROVE_RCU=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_SPINLOCK is not set/CONFIG_DEBUG_SPINLOCK=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_VM is not set/CONFIG_DEBUG_VM=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/CONFIG_DEBUG_SLEEP_IN_IRQ=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAULT_INJECTION is not set/CONFIG_FAULT_INJECTION=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAILSLAB is not set/CONFIG_FAILSLAB=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAIL_PAGE_ALLOC is not set/CONFIG_FAIL_PAGE_ALLOC=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAIL_IO_TIMEOUT is not set/CONFIG_FAIL_IO_TIMEOUT=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAIL_MAKE_REQUEST is not set/CONFIG_FAIL_MAKE_REQUEST=y/' config-nodebug + @perl -pi -e 's/# CONFIG_FAIL_MMC_REQUEST is not set/CONFIG_FAIL_MMC_REQUEST=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAULT_INJECTION_DEBUG_FS is not set/CONFIG_FAULT_INJECTION_DEBUG_FS=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set/CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_SG is not set/CONFIG_DEBUG_SG=y/' config-nodebug @@ -66,7 +66,6 @@ debug: @perl -pi -e 's/# CONFIG_DMA_API_DEBUG is not set/CONFIG_DMA_API_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_PM_TEST_SUSPEND is not set/CONFIG_PM_TEST_SUSPEND=y/' config-generic @perl -pi -e 's/# CONFIG_PM_ADVANCED_DEBUG is not set/CONFIG_PM_ADVANCED_DEBUG=y/' config-generic - @perl -pi -e 's/# CONFIG_BOOT_TRACER is not set/CONFIG_BOOT_TRACER=y/' config-generic @perl -pi -e 's/# CONFIG_B43_DEBUG is not set/CONFIG_B43_DEBUG=y/' config-generic @perl -pi -e 's/# CONFIG_B43LEGACY_DEBUG is not set/CONFIG_B43LEGACY_DEBUG=y/' config-generic @perl -pi -e 's/# CONFIG_MMIOTRACE is not set/CONFIG_MMIOTRACE=y/' config-nodebug @@ -77,12 +76,11 @@ debug: @perl -pi -e 's/# CONFIG_EXT4_DEBUG is not set/CONFIG_EXT4_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/CONFIG_DEBUG_PERF_USE_VMALLOC=y/' config-nodebug @perl -pi -e 's/# CONFIG_JBD2_DEBUG is not set/CONFIG_JBD2_DEBUG=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_CFQ_IOSCHED is not set/CONFIG_DEBUG_CFQ_IOSCHED=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_BLK_CGROUP is not set/CONFIG_DEBUG_BLK_CGROUP=y/' config-nodebug @perl -pi -e 's/# CONFIG_DRBD_FAULT_INJECTION is not set/CONFIG_DRBD_FAULT_INJECTION=y/' config-nodebug @perl -pi -e 's/# CONFIG_ATH_DEBUG is not set/CONFIG_ATH_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_CARL9170_DEBUGFS is not set/CONFIG_CARL9170_DEBUGFS=y/' config-nodebug @perl -pi -e 's/# CONFIG_IWLWIFI_DEVICE_TRACING is not set/CONFIG_IWLWIFI_DEVICE_TRACING=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set/CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y/' config-nodebug @perl -pi -e 's/# CONFIG_DMADEVICES_DEBUG is not set/CONFIG_DMADEVICES_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_DMADEVICES_VDEBUG is not set/CONFIG_DMADEVICES_VDEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_CEPH_LIB_PRETTYDEBUG is not set/CONFIG_CEPH_LIB_PRETTYDEBUG=y/' config-nodebug @@ -93,21 +91,22 @@ debug: @perl -pi -e 's/# CONFIG_DEBUG_PER_CPU_MAPS is not set/CONFIG_DEBUG_PER_CPU_MAPS=y/' config-nodebug @perl -pi -e 's/# CONFIG_TEST_LIST_SORT is not set/CONFIG_TEST_LIST_SORT=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/CONFIG_DEBUG_ATOMIC_SLEEP=y/' config-nodebug - - @perl -pi -e 's/# CONFIG_DEBUG_SET_MODULE_RONX is not set/CONFIG_DEBUG_SET_MODULE_RONX=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DETECT_HUNG_TASK is not set/CONFIG_DETECT_HUNG_TASK=y/' config-nodebug + @perl -pi -e 's/# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set/CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_KMEMLEAK is not set/CONFIG_DEBUG_KMEMLEAK=y/' config-nodebug @# just in case we're going from extremedebug -> debug @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug - @perl -pi -e 's/CONFIG_NR_CPUS=256/CONFIG_NR_CPUS=512/' config-x86_64-generic + @perl -pi -e 's/# CONFIG_MAXSMP is not set/CONFIG_MAXSMP=y/' config-x86-generic + + # Try out UAS in rawhide builds. + @perl -pi -e 's/# CONFIG_USB_UAS is not set/CONFIG_USB_UAS=m/' config-generic @perl -pi -e 's/^%define debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec @perl -pi -e 's/^%define rawhide_skip_docs 0/%define rawhide_skip_docs 1/' kernel.spec + @rpmdev-bumpspec -c "Reenable debugging options." kernel.spec -nodebuginfo: - @perl -pi -e 's/^%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 1\}/%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 0\}/' kernel.spec -nodebug: release - @perl -pi -e 's/^%define debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec release: @perl -pi -e 's/CONFIG_SLUB_DEBUG_ON=y/# CONFIG_SLUB_DEBUG_ON is not set/' config-nodebug @perl -pi -e 's/CONFIG_LOCK_STAT=y/# CONFIG_LOCK_STAT is not set/' config-nodebug @@ -115,18 +114,17 @@ release: @perl -pi -e 's/CONFIG_DEBUG_SLAB=y/# CONFIG_DEBUG_SLAB is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_MUTEXES=y/# CONFIG_DEBUG_MUTEXES is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_RT_MUTEXES=y/# CONFIG_DEBUG_RT_MUTEXES is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_RWSEMS=y/# CONFIG_DEBUG_RWSEMS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_LOCK_ALLOC=y/# CONFIG_DEBUG_LOCK_ALLOC is not set/' config-nodebug @perl -pi -e 's/CONFIG_PROVE_LOCKING=y/# CONFIG_PROVE_LOCKING is not set/' config-nodebug @perl -pi -e 's/CONFIG_PROVE_RCU=y/# CONFIG_PROVE_RCU is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_SPINLOCK=y/# CONFIG_DEBUG_SPINLOCK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_VM=y/# CONFIG_DEBUG_VM is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_SLEEP_IN_IRQ=y/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAULT_INJECTION=y/# CONFIG_FAULT_INJECTION is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAILSLAB=y/# CONFIG_FAILSLAB is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAIL_PAGE_ALLOC=y/# CONFIG_FAIL_PAGE_ALLOC is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAIL_IO_TIMEOUT=y/# CONFIG_FAIL_IO_TIMEOUT is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAIL_MAKE_REQUEST=y/# CONFIG_FAIL_MAKE_REQUEST is not set/' config-nodebug + @perl -pi -e 's/CONFIG_FAIL_MMC_REQUEST=y/# CONFIG_FAIL_MMC_REQUEST is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAULT_INJECTION_DEBUG_FS=y/# CONFIG_FAULT_INJECTION_DEBUG_FS is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y/# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_SG=y/# CONFIG_DEBUG_SG is not set/' config-nodebug @@ -143,9 +141,8 @@ release: @perl -pi -e 's/CONFIG_SYSCTL_SYSCALL_CHECK=y/# CONFIG_SYSCTL_SYSCALL_CHECK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_NOTIFIERS=y/# CONFIG_DEBUG_NOTIFIERS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMA_API_DEBUG=y/# CONFIG_DMA_API_DEBUG is not set/' config-nodebug - @perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/#\ CONFIG_PM_TEST_SUSPEND\ is\ not\ set/' config-generic - @perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/#\ CONFIG_PM_ADVANCED_DEBUG\ is\ not\ set/' config-generic - @perl -pi -e 's/CONFIG_BOOT_TRACER=y/#\ CONFIG_BOOT_TRACER\ is\ not\ set/' config-generic + @perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/# CONFIG_PM_TEST_SUSPEND is not set/' config-generic + @perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/# CONFIG_PM_ADVANCED_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_B43_DEBUG=y/# CONFIG_B43_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_B43LEGACY_DEBUG=y/# CONFIG_B43LEGACY_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_MMIOTRACE=y/# CONFIG_MMIOTRACE is not set/' config-nodebug @@ -156,12 +153,11 @@ release: @perl -pi -e 's/CONFIG_EXT4_DEBUG=y/# CONFIG_EXT4_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_PERF_USE_VMALLOC=y/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/' config-nodebug @perl -pi -e 's/CONFIG_JBD2_DEBUG=y/# CONFIG_JBD2_DEBUG is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_CFQ_IOSCHED=y/# CONFIG_DEBUG_CFQ_IOSCHED is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_BLK_CGROUP=y/# CONFIG_DEBUG_BLK_CGROUP is not set/' config-nodebug @perl -pi -e 's/CONFIG_DRBD_FAULT_INJECTION=y/# CONFIG_DRBD_FAULT_INJECTION is not set/' config-nodebug @perl -pi -e 's/CONFIG_ATH_DEBUG=y/# CONFIG_ATH_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_CARL9170_DEBUGFS=y/# CONFIG_CARL9170_DEBUGFS is not set/' config-nodebug @perl -pi -e 's/CONFIG_IWLWIFI_DEVICE_TRACING=y/# CONFIG_IWLWIFI_DEVICE_TRACING is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y/# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMADEVICES_DEBUG=y/# CONFIG_DMADEVICES_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMADEVICES_VDEBUG=y/# CONFIG_DMADEVICES_VDEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_CEPH_LIB_PRETTYDEBUG=y/# CONFIG_CEPH_LIB_PRETTYDEBUG is not set/' config-nodebug @@ -172,144 +168,37 @@ release: @perl -pi -e 's/CONFIG_DEBUG_PER_CPU_MAPS=y/# CONFIG_DEBUG_PER_CPU_MAPS is not set/' config-nodebug @perl -pi -e 's/CONFIG_TEST_LIST_SORT=y/# CONFIG_TEST_LIST_SORT is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_ATOMIC_SLEEP=y/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DETECT_HUNG_TASK=y/# CONFIG_DETECT_HUNG_TASK is not set/' config-nodebug + @perl -pi -e 's/CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y/# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_KMEMLEAK=y/# CONFIG_DEBUG_KMEMLEAK is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_SET_MODULE_RONX=y/# CONFIG_DEBUG_SET_MODULE_RONX is not set/' config-nodebug - + # Undo anything that make extremedebug might have set @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-debug @perl -pi -e 's/CONFIG_DEBUG_PAGEALLOC=y/# CONFIG_DEBUG_PAGEALLOC is not set/' config-nodebug - @perl -pi -e 's/CONFIG_NR_CPUS=512/CONFIG_NR_CPUS=256/' config-x86_64-generic + # Change defaults back to sane things. + @perl -pi -e 's/CONFIG_MAXSMP=y/# CONFIG_MAXSMP is not set/' config-x86-generic + + # Disable UAS for release until it's ready. (#717633, #744099) + @perl -pi -e 's/CONFIG_USB_UAS=m/# CONFIG_USB_UAS is not set/' config-generic @perl -pi -e 's/^%define debugbuildsenabled 0/%define debugbuildsenabled 1/' kernel.spec @perl -pi -e 's/^%define rawhide_skip_docs 1/%define rawhide_skip_docs 0/' kernel.spec + @rpmdev-bumpspec -c "Disable debugging options." kernel.spec -reconfig: - @rm -f kernel-*-config - @VERSION=$(KVERSION) make -f Makefile.config configs - @scripts/reconfig.sh +nodebuginfo: + @perl -pi -e 's/^%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 1\}/%define with_debuginfo %\{\?_without_debuginfo: 0\} %\{\?\!_without_debuginfo: 0\}/' kernel.spec +nodebug: release + @perl -pi -e 's/^%define debugbuildsenabled 1/%define debugbuildsenabled 0/' kernel.spec unused-kernel-patches: @for f in *.patch; do if [ -e $$f ]; then (egrep -q "^Patch[[:digit:]]+:[[:space:]]+$$f" $(SPECFILE) || echo "Unused: $$f") && egrep -q "^ApplyPatch[[:space:]]+$$f|^ApplyOptionalPatch[[:space:]]+$$f" $(SPECFILE) || echo "Unapplied: $$f"; fi; done -# since i386 isn't a target... -compile compile-short: DIST_DEFINES += --target $(shell uname -m) +ifeq ($(MAKECMDGOALS),me a sandwich) +.PHONY: me a sandwich +me a: + @: -# 'make local' also needs to build the noarch firmware package -local: noarch - -# -# Hacks for building vanilla (unpatched) kernel rpms. -# Use "make vanilla-TARGET" like "make TARGET" (make vanilla-scratch-build). -# -vanilla-%: $(SPECFILE:.spec=-vanilla.spec) - @$(MAKE) $* SPECFILE=$< - -$(SPECFILE:.spec=-vanilla.spec): $(SPECFILE) - @rm -f $@ - (echo %define nopatches 1; cat $<) > $@ - -#scratch-build: NAME = $(shell rpm $(RPM_DEFINES) $(DIST_DEFINES) -q --qf "%{NAME}\n" --specfile $(SPECFILE)| head -1) -#scratch-build: test-srpm -# $(BUILD_CLIENT) build $(BUILD_FLAGS) --scratch $(TARGET) \ -# $(SRCRPMDIR)/$(NAME)-$(VERSION)-$(RELEASE).src.rpm - -# Dismal kludge for building via brew from cvs after "make vanilla-tag". -ifdef BEEHIVE_SRPM_BUILD -export CHECKOUT_TAG ?= $(shell sed s/^.// CVS/Tag) -tag-pattern = $(TAG_NAME)-$(TAG_VERSION)-0_%_$(TAG_RELEASE) -ifeq (,$(filter-out $(tag-pattern),$(CHECKOUT_TAG))) -variant := $(patsubst $(tag-pattern),%,$(CHECKOUT_TAG)) -srpm: SPECFILE := $(wildcard $(SPECFILE:.spec=-$(variant).spec) \ - $(SPECFILE:.spec=.t.$(variant).spec)) -srpm beehive-sprm: RELEASE := 0.$(variant).$(RELEASE) -endif -endif - -# -# Hacks for building kernel rpms from upstream code plus local GIT branches. -# Use "make git/BRANCH/TARGET" like "make TARGET". -# Use "make git/BRANCH-fedora/TARGET" to include Fedora patches on top. -# -ifndef GIT_SPEC -git/%: - @$(MAKE) GIT_SPEC=$(subst /,-,$(*D)) git-$(*F) -else -git-%: $(SPECFILE:.spec=.t.$(GIT_SPEC).spec) - @$(MAKE) GIT_SPEC= $* SPECFILE=$< -endif - -# -# Your git-branches.mk file can define GIT_DIR, e.g.: -# GIT_DIR = ${HOME}/kernel/.git -# Make sure GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL are also set -# or your rpm changelogs will look like crap. -# -# For each branch it can define a variable branch-BRANCH or tag-BRANCH -# giving the parent of BRANCH to diff against in a separate patch. If -# the parent is unknown, it will use $(branch-upstream) defaulting to -# "refs/remotes/upstream/master". -# -# Defining tag-BRANCH means the tag corresponds to an upstream patch in -# the sources file, so that is used instead of generating a patch with -# git. If there is no tag-upstream defined, it will figure out a vNNN -# tag or vNNN-gitN pseudo-tag from the last patch in the sources file. -# For example: -# tag-some-hacks = v2.6.21-rc5 -# branch-more-hacks = some-hacks -# Leads to patches: -# git diff v2.6.21-rc5..more-hacks > linux-2.6.21-rc5-some-hacks.patch -# git diff some-hacks..more-hacks > linux-2.6.21-rc5-more-hacks.patch -# Whereas having no git-branches.mk at all but doing -# "make GIT_DIR=... git/mybranch/test-srpm" does: -# id=`cat patch-2.6.21-rc5-git4.id` # auto-fetched via upstream file -# git diff $id..upstream > linux-2.6.21-rc5-git4-upstream.patch -# git diff upstream..mybranch > linux-2.6.21-rc5-git4-mybranch.patch -# If the upstream patch (or any branch patch) is empty it's left out. -# -git-branches.mk:; --include git-branches.mk - -branch-upstream ?= refs/remotes/upstream/master - -ifdef GIT_DIR -export GIT_DIR -export GIT_AUTHOR_NAME -export GIT_AUTHOR_EMAIL -gen-patches ?= gen-patches - -ifndef havespec -$(SPECFILE:.spec=.t.%-fedora.spec): $(SPECFILE) $(gen-patches) FORCE - ./$(gen-patches) --fedora < $< > $@ $(gen-patches-args) -$(SPECFILE:.spec=.t.%.spec): $(SPECFILE) $(gen-patches) FORCE - ./$(gen-patches) < $< > $@ $(gen-patches-args) -.PRECIOUS: $(SPECFILE:.spec=.t.%.spec) $(SPECFILE:.spec=.t.%-fedora.spec) -endif - -spec-%: $(SPECFILE:.spec=.t.%.spec) ; -$(SPECFILE):; -FORCE:; - -branch-of-* = $(firstword $(head-$*) $*) -gen-patches-args = --name $* v$(KVERSION) $(call heads,$(branch-of-*)) -define heads -$(if $(tag-$1),$(filter-out v$(KVERSION),$(tag-$1)),\ - $(call heads,$(firstword $(branch-$1) $(branch-upstream)))) $1 -endef - -files-%-fedora: - @echo $(SPECFILE:.spec=.t.$*-fedora.spec) - @$(call list-patches,$(branch-of-*)) -files-%: - @echo $(SPECFILE:.spec=.t.$*.spec) - @$(call list-patches,$(branch-of-*)) -define list-patches -$(if $(tag-$1),version=$(patsubst v%,%,$(tag-$1)),\ - $(call list-patches,$(firstword $(branch-$1) $(branch-upstream)))); \ -echo linux-$${version}-$(patsubst refs/remotes/%/master,%,$1).patch -endef - -ifndef tag-$(branch-upstream) -tag-$(branch-upstream) := $(shell \ - sed -n 's/^.* *//;s/\.bz2$$//;s/patch-/v/;/^v/h;$${g;p}' sources) -endif +sandwich: + @[ `id -u` -ne 0 ] && echo "What? Make it yourself." || echo Okay. endif diff --git a/Makefile.config b/Makefile.config index 53812fa9b..0e6587f56 100644 --- a/Makefile.config +++ b/Makefile.config @@ -8,13 +8,12 @@ CONFIGFILES = \ $(CFG)-i686.config $(CFG)-i686-debug.config \ $(CFG)-i686-PAE.config $(CFG)-i686-PAEdebug.config \ $(CFG)-x86_64.config $(CFG)-x86_64-debug.config \ - $(CFG)-s390x.config $(CFG)-arm.config \ + $(CFG)-s390x.config \ $(CFG)-ppc.config $(CFG)-ppc-smp.config \ $(CFG)-sparc64.config \ - $(CFG)-ppc64.config $(CFG)-ppc64-debug.config \ - $(CFG)-ia64.config + $(CFG)-ppc64.config $(CFG)-ppc64-debug.config -PLATFORMS = x86 x86_64 powerpc powerpc32 powerpc64 s390x ia64 sparc64 +PLATFORMS = x86 x86_64 powerpc powerpc32 powerpc64 s390x sparc64 TEMPFILES = $(addprefix temp-, $(addsuffix -generic, $(PLATFORMS))) configs: $(CONFIGFILES) @@ -32,16 +31,22 @@ temp-generic: config-generic temp-debug-generic: config-generic cat config-generic config-debug > temp-debug-generic -temp-x86-generic: config-x86-generic temp-generic +temp-x86-32: config-x86-32-generic config-x86-generic perl merge.pl $^ > $@ -temp-x86-debug-generic: config-x86-generic temp-debug-generic +temp-x86-32-generic: temp-x86-32 temp-generic perl merge.pl $^ > $@ -temp-x86_64-generic: config-x86_64-generic temp-generic +temp-x86-debug-generic: temp-x86-32 temp-debug-generic perl merge.pl $^ > $@ -temp-x86_64-debug-generic: config-x86_64-generic temp-debug-generic +temp-x86-64: config-x86_64-generic config-x86-generic + perl merge.pl $^ > $@ + +temp-x86_64-generic: temp-x86-64 temp-generic + perl merge.pl $^ > $@ + +temp-x86_64-debug-generic: temp-x86-64 temp-debug-generic perl merge.pl $^ > $@ temp-sparc64-generic: config-sparc64-generic temp-generic @@ -59,16 +64,13 @@ temp-powerpc32-generic: config-powerpc32-generic temp-powerpc-generic temp-s390-generic: config-s390x temp-generic perl merge.pl $^ > $@ -temp-ia64-generic: config-ia64-generic temp-generic - perl merge.pl $^ > $@ - -kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-generic +kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-32-generic perl merge.pl $^ i386 > $@ kernel-$(VERSION)-i686-PAEdebug.config: config-i686-PAE temp-x86-debug-generic perl merge.pl $^ i386 > $@ -kernel-$(VERSION)-i686.config: /dev/null temp-x86-generic +kernel-$(VERSION)-i686.config: /dev/null temp-x86-32-generic perl merge.pl $^ i386 > $@ kernel-$(VERSION)-i686-debug.config: /dev/null temp-x86-debug-generic @@ -92,14 +94,8 @@ kernel-$(VERSION)-ppc64-debug.config: config-powerpc64 temp-powerpc-debug-generi kernel-$(VERSION)-s390x.config: config-s390x temp-s390-generic perl merge.pl $^ s390 > $@ -kernel-$(VERSION)-arm.config: config-arm temp-generic - perl merge.pl $^ arm > $@ - kernel-$(VERSION)-ppc.config: /dev/null temp-powerpc32-generic perl merge.pl $^ powerpc > $@ kernel-$(VERSION)-ppc-smp.config: config-powerpc32-smp temp-powerpc32-generic perl merge.pl $^ powerpc > $@ - -kernel-$(VERSION)-ia64.config: /dev/null temp-ia64-generic - perl merge.pl $^ ia64 > $@ diff --git a/SCSI-mvsas-Fix-oops-when-ata-commond-timeout.patch b/SCSI-mvsas-Fix-oops-when-ata-commond-timeout.patch new file mode 100644 index 000000000..0d83e8d03 --- /dev/null +++ b/SCSI-mvsas-Fix-oops-when-ata-commond-timeout.patch @@ -0,0 +1,102 @@ +From 95ab000388974d8ffef8257306b4be6e8778b768 Mon Sep 17 00:00:00 2001 +From: Jianpeng Ma +Date: Sat, 4 Aug 2012 10:34:14 +0800 +Subject: [PATCH] [SCSI] mvsas: Fix oops when ata commond timeout. + +Kernel message follows: + +[ 511.712011] sd 11:0:0:0: [sdf] command ffff8800a4e81400 timed out +[ 511.712022] sas: Enter sas_scsi_recover_host busy: 1 failed: 1 +[ 511.712024] sas: trying to find task 0xffff8800a4d24c80 +[ 511.712026] sas: sas_scsi_find_task: aborting task 0xffff8800a4d24c80 +[ 511.712029] drivers/scsi/mvsas/mv_sas.c 1631:mvs_abort_task() +mvi=ffff8800b5300000 task=ffff8800a4d24c80 slot=ffff8800b5325038 +slot_idx=x0 +[ 511.712035] BUG: unable to handle kernel NULL pointer dereference at +0000000000000058 +[ 511.712040] IP: [] _raw_spin_lock_irqsave+0xc/0x30 +[ 511.712047] PGD 0 +[ 511.712049] Oops: 0002 [#1] SMP +[ 511.712052] Modules linked in: mvsas libsas scsi_transport_sas +raid456 async_pq async_xor xor async_memcpy async_raid6_recov raid6_pq +async_tx [last unloaded: mvsas] +[ 511.712062] CPU 3 +[ 511.712066] Pid: 7322, comm: scsi_eh_11 Not tainted 3.5.0+ #106 To Be +Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M. +[ 511.712068] RIP: 0010:[] [] +_raw_spin_lock_irqsave+0xc/0x30 +[ 511.712073] RSP: 0018:ffff880098d3bcb0 EFLAGS: 00010086 +[ 511.712074] RAX: 0000000000000286 RBX: 0000000000000058 RCX: +00000000000000c3 +[ 511.712076] RDX: 0000000000000100 RSI: 0000000000000046 RDI: +0000000000000058 +[ 511.712078] RBP: ffff880098d3bcb0 R08: 000000000000000a R09: +0000000000000000 +[ 511.712080] R10: 00000000000004e8 R11: 00000000000004e7 R12: +ffff8800a4d24c80 +[ 511.712082] R13: 0000000000000050 R14: ffff8800b5325038 R15: +ffff8800a4eafe00 +[ 511.712084] FS: 0000000000000000(0000) GS:ffff8800bdb80000(0000) +knlGS:0000000000000000 +[ 511.712086] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +[ 511.712088] CR2: 0000000000000058 CR3: 00000000a4ce6000 CR4: +00000000000407e0 +[ 511.712090] DR0: 0000000000000000 DR1: 0000000000000000 DR2: +0000000000000000 +[ 511.712091] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: +0000000000000400 +[ 511.712093] Process scsi_eh_11 (pid: 7322, threadinfo +ffff880098d3a000, task ffff8800a61dde40) +[ 511.712095] Stack: +[ 511.712096] ffff880098d3bce0 ffffffff81060683 ffff880000000000 +0000000000000000 +[ 511.712099] ffff8800a4d24c80 ffff8800b5300000 ffff880098d3bcf0 +ffffffffa0076a88 +[ 511.712102] ffff880098d3bd50 ffffffffa0079bb5 ffff880000000000 +ffff880000000018 +[ 511.712106] Call Trace: +[ 511.712110] [] complete+0x23/0x60 +[ 511.712115] [] mvs_tmf_timedout+0x18/0x20 [mvsas] +[ 511.712119] [] mvs_slot_complete+0x765/0x7d0 +[mvsas] +[ 511.712125] [] sas_scsi_recover_host+0x55d/0xdb0 +[libsas] +[ 511.712128] [] ? idle_balance+0xe0/0x130 +[ 511.712133] [] scsi_error_handler+0xcc/0x470 +[ 511.712136] [] ? __schedule+0x370/0x730 +[ 511.712139] [] ? __wake_up_common+0x58/0x90 +[ 511.712142] [] ? scsi_eh_get_sense+0x110/0x110 +[ 511.712146] [] kthread+0x8e/0xa0 +[ 511.712150] [] kernel_thread_helper+0x4/0x10 +[ 511.712153] [] ? flush_kthread_work+0x120/0x120 +[ 511.712156] [] ? gs_change+0xb/0xb +[ 511.712157] Code: 8a 00 01 00 00 89 d0 f0 66 0f b1 0f 66 39 d0 0f 94 +c0 0f b6 c0 5d c3 0f 1f 84 00 00 00 00 00 55 48 89 e5 9c 58 fa ba 00 01 +00 00 66 0f c1 17 0f b6 ce 38 d1 74 11 0f 1f 84 00 00 00 00 00 f3 +[ 511.712191] RIP [] _raw_spin_lock_irqsave+0xc/0x30 +[ 511.712194] RSP +[ 511.712196] CR2: 0000000000000058 +[ 511.712198] ---[ end trace a781c7b1e65db92c ]--- + +Signed-off-by: Jianpeng Ma +Signed-off-by: James Bottomley +--- + drivers/scsi/mvsas/mv_sas.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c +index 4539d59..a3776d6 100644 +--- a/drivers/scsi/mvsas/mv_sas.c ++++ b/drivers/scsi/mvsas/mv_sas.c +@@ -1629,7 +1629,7 @@ int mvs_abort_task(struct sas_task *task) + mv_dprintk("mvs_abort_task() mvi=%p task=%p " + "slot=%p slot_idx=x%x\n", + mvi, task, slot, slot_idx); +- mvs_tmf_timedout((unsigned long)task); ++ task->task_state_flags |= SAS_TASK_STATE_ABORTED; + mvs_slot_task_free(mvi, task, slot, slot_idx); + rc = TMF_RESP_FUNC_COMPLETE; + goto out; +-- +1.8.0 + diff --git a/TODO b/TODO index 968324422..24e57f99a 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,6 @@ Empty * linux-2.6-debug-taint-vm.patch -* linux-2.6-debug-vm-would-have-oomkilled.patch TODO: Push upstream * linux-2.6-acpi-video-dos.patch @@ -23,9 +22,6 @@ Rolandware that is used by the debuginfo generation. Possibly upstreamable ? -* linux-2.6.29-sparc-IOC_TYPECHECK.patch - Responsible: Spot/Dennis. - * linux-2.6-v4l-dvb-uvcvideo-update.patch Responsible: Hans. @@ -43,11 +39,7 @@ One half of the remaining exec-shield diff. davej bugged Ingo again on Jun 17 2011 about upstreaming. -* runtime_pm_fixups.patch -* linux-2.6-usb-pci-autosuspend.patch -* linux-2.6-enable-more-pci-autosuspend.patch * linux-2.6-acpi-debug-infinite-loop.patch -* acpi-ec-add-delay-before-write.patch Responsible: mjg59 * linux-2.6-v4l-dvb-experimental.patch diff --git a/USB-report-submission-of-active-URBs.patch b/USB-report-submission-of-active-URBs.patch new file mode 100644 index 000000000..4496c913a --- /dev/null +++ b/USB-report-submission-of-active-URBs.patch @@ -0,0 +1,46 @@ +commit 2f02bc8af3abb846823811af65ec6cc46a4d525d +Author: Alan Stern +Date: Wed Nov 7 16:35:00 2012 -0500 + + USB: report submission of active URBs + + This patch (as1633) changes slightly the way usbcore handled + submissions of URBs that are already active. It will now return + -EBUSY rather than -EINVAL, and it will call WARN_ONCE to draw + people's attention to the bug. + + Signed-off-by: Alan Stern + Signed-off-by: Greg Kroah-Hartman + +diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt +index 8d1e2a9..9c3eb84 100644 +--- a/Documentation/usb/error-codes.txt ++++ b/Documentation/usb/error-codes.txt +@@ -21,6 +21,8 @@ Non-USB-specific: + + USB-specific: + ++-EBUSY The URB is already active. ++ + -ENODEV specified USB-device or bus doesn't exist + + -ENOENT specified interface or endpoint does not exist or +diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c +index 3662287..e0d9d94 100644 +--- a/drivers/usb/core/urb.c ++++ b/drivers/usb/core/urb.c +@@ -321,8 +321,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) + struct usb_host_endpoint *ep; + int is_out; + +- if (!urb || urb->hcpriv || !urb->complete) ++ if (!urb || !urb->complete) + return -EINVAL; ++ if (urb->hcpriv) { ++ WARN_ONCE(1, "URB %p submitted while active\n", urb); ++ return -EBUSY; ++ } ++ + dev = urb->dev; + if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) + return -ENODEV; diff --git a/acpi-ec-add-delay-before-write.patch b/acpi-ec-add-delay-before-write.patch deleted file mode 100644 index f1cb50817..000000000 --- a/acpi-ec-add-delay-before-write.patch +++ /dev/null @@ -1,51 +0,0 @@ -https://bugzilla.kernel.org/show_bug.cgi?id=14733#c41 - -diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c -index 27e0b92..09fbb69 100644 ---- a/drivers/acpi/ec.c -+++ b/drivers/acpi/ec.c -@@ -226,6 +226,7 @@ static int ec_poll(struct acpi_ec *ec) - if (ec_transaction_done(ec)) - return 0; - } else { -+ msleep(1); - if (wait_event_timeout(ec->wait, - ec_transaction_done(ec), - msecs_to_jiffies(1))) -@@ -233,8 +234,8 @@ static int ec_poll(struct acpi_ec *ec) - } - advance_transaction(ec, acpi_ec_read_status(ec)); - } while (time_before(jiffies, delay)); -- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) -- break; -+// if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) -+// break; - pr_debug(PREFIX "controller reset, restart transaction\n"); - spin_lock_irqsave(&ec->curr_lock, flags); - start_transaction(ec); -@@ -271,15 +272,24 @@ static int ec_check_ibf0(struct acpi_ec *ec) - return (status & ACPI_EC_FLAG_IBF) == 0; - } - -+/* try to clean input buffer with burst_disable transaction */ -+static int acpi_ec_clean_buffer(struct acpi_ec *ec) -+{ -+ struct transaction t = {.command = ACPI_EC_BURST_DISABLE, -+ .wdata = NULL, .rdata = NULL, -+ .wlen = 0, .rlen = 0}; -+ return acpi_ec_transaction_unlocked(ec, &t); -+} -+ - static int ec_wait_ibf0(struct acpi_ec *ec) - { - unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); - /* interrupt wait manually if GPE mode is not active */ - while (time_before(jiffies, delay)) - if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), - msecs_to_jiffies(1))) - return 0; -- return -ETIME; -+ return acpi_ec_clean_buffer(ec); - } - - static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) diff --git a/acpi-sony-nonvs-blacklist.patch b/acpi-sony-nonvs-blacklist.patch new file mode 100644 index 000000000..db500e8bf --- /dev/null +++ b/acpi-sony-nonvs-blacklist.patch @@ -0,0 +1,38 @@ +diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c +index 3ed80b2..17fc718 100644 +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -390,6 +390,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + }, + { + .callback = init_nvs_nosave, ++ .ident = "Sony Vaio VGN-FW21E", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), ++ }, ++ }, ++ { ++ .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c +index 0e46fae..6d9a3ab 100644 +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -398,6 +398,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + }, + { + .callback = init_nvs_nosave, ++ .ident = "Sony Vaio VPCEB17FX", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), ++ }, ++ }, ++ { ++ .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch deleted file mode 100644 index 26477ccce..000000000 --- a/add-appleir-usb-driver.patch +++ /dev/null @@ -1,702 +0,0 @@ -From e11e9e78799a7641fe0dc5289f35f2604a4b71a3 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Sun, 17 Jan 2010 00:40:15 +0000 -Subject: [PATCH] Input: add appleir USB driver - -This driver was originally written by James McKenzie, updated by -Greg Kroah-Hartman, further updated by myself, with suspend support -added. - -More recent versions of the IR receiver are also supported through -a patch by Alex Karpenko. The patch also adds support for the 2nd -and 5th generation of the controller, and the menu key on newer -brushed metal remotes. - -Tested on a MacbookAir1,1 - -Signed-off-by: Bastien Nocera ---- - Documentation/input/appleir.txt | 46 ++++ - drivers/hid/hid-apple.c | 4 - - drivers/hid/hid-core.c | 7 +- - drivers/hid/hid-ids.h | 5 +- - drivers/input/misc/Kconfig | 13 + - drivers/input/misc/Makefile | 1 + - drivers/input/misc/appleir.c | 519 +++++++++++++++++++++++++++++++++++++++ - 7 files changed, 588 insertions(+), 7 deletions(-) - create mode 100644 Documentation/input/appleir.txt - create mode 100644 drivers/input/misc/appleir.c - -diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt -new file mode 100644 -index 0000000..db637fb ---- /dev/null -+++ b/Documentation/input/appleir.txt -@@ -0,0 +1,46 @@ -+Apple IR receiver Driver (appleir) -+---------------------------------- -+ Copyright (C) 2009 Bastien Nocera -+ -+The appleir driver is a kernel input driver to handle Apple's IR -+receivers (and associated remotes) in the kernel. -+ -+The driver is an input driver which only handles "official" remotes -+as built and sold by Apple. -+ -+Authors -+------- -+ -+James McKenzie (original driver) -+Alex Karpenko (05ac:8242 support) -+Greg Kroah-Hartman (cleanups and original submission) -+Bastien Nocera (further cleanups, brushed metal "enter" -+button support and suspend support) -+ -+Supported hardware -+------------------ -+ -+- All Apple laptops and desktops from 2005 onwards, except: -+ - the unibody Macbook (2009) -+ - Mac Pro (all versions) -+- Apple TV (all revisions prior to September 2010) -+ -+The remote will only support the 6 (old white) or 7 (brushed metal) buttons -+of the remotes as sold by Apple. See the next section if you want to use -+other remotes or want to use lirc with the device instead of the kernel driver. -+ -+Using lirc (native) instead of the kernel driver -+------------------------------------------------ -+ -+First, you will need to disable the kernel driver for the receiver. -+ -+This can be achieved by passing quirks to the usbhid driver. -+The quirk line would be: -+usbhid.quirks=0x05ac:0x8242:0x40000010 -+ -+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this) -+With 0x8242 being the product ID (check the output of lsusb for your hardware) -+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE" -+ -+This should force the creation of a hiddev device for the receiver, and -+make it usable under lirc. -diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index bba05d0..0059d5a 100644 ---- a/drivers/hid/hid-apple.c -+++ b/drivers/hid/hid-apple.c -@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev) - } - - static const struct hid_device_id apple_devices[] = { -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL), -- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4), -- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), - .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, - -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index baa25ad..abc5bd7 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -1244,8 +1244,6 @@ static const struct hid_device_id hid_blacklist[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, -@@ -1577,6 +1575,11 @@ static const struct hid_device_id hid_ignore_list[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, - { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 11af537..360a5ca 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -100,8 +100,11 @@ - #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b - #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a - #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b --#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 -+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 -+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 - #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 - - #define USB_VENDOR_ID_ASUS 0x0486 - #define USB_DEVICE_ID_ASUS_T91MT 0x0185 -diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index 60de906..2f2f2e7 100644 ---- a/drivers/input/misc/Kconfig -+++ b/drivers/input/misc/Kconfig -@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE - To compile this driver as a module, choose M here: the module will - be called keyspan_remote. - -+config INPUT_APPLEIR -+ tristate "Apple infrared receiver (built in)" -+ depends on USB_ARCH_HAS_HCD -+ select USB -+ help -+ Say Y here if you want to use a Apple infrared remote control. All -+ the Apple computers from 2005 onwards include such a port, except -+ the unibody Macbook (2009), and Mac Pros. This receiver is also -+ used in the Apple TV set-top box prior to the 2010 model. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called appleir. -+ - config INPUT_POWERMATE - tristate "Griffin PowerMate and Contour Jog support" - depends on USB_ARCH_HAS_HCD -diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index 1fe1f6c..d5ef2b9 100644 ---- a/drivers/input/misc/Makefile -+++ b/drivers/input/misc/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o - obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o - obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o - obj-$(CONFIG_INPUT_APANEL) += apanel.o -+obj-$(CONFIG_INPUT_APPLEIR) += appleir.o - obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o - obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o - obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o -diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c -new file mode 100644 -index 0000000..3817a3c ---- /dev/null -+++ b/drivers/input/misc/appleir.c -@@ -0,0 +1,519 @@ -+/* -+ * appleir: USB driver for the apple ir device -+ * -+ * Original driver written by James McKenzie -+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman -+ * -+ * Copyright (C) 2006 James McKenzie -+ * Copyright (C) 2008 Greg Kroah-Hartman -+ * Copyright (C) 2008 Novell 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, version 2. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_VERSION "v1.2" -+#define DRIVER_AUTHOR "James McKenzie" -+#define DRIVER_DESC "Apple infrared receiver driver" -+#define DRIVER_LICENSE "GPL" -+ -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE(DRIVER_LICENSE); -+ -+#define USB_VENDOR_ID_APPLE 0x05ac -+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 -+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 -+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 -+ -+#define URB_SIZE 32 -+ -+#define MAX_KEYS 9 -+#define MAX_KEYS_MASK (MAX_KEYS - 1) -+ -+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) -+ -+static int debug; -+module_param(debug, int, 0644); -+MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); -+ -+/* I have two devices both of which report the following */ -+/* 25 87 ee 83 0a + */ -+/* 25 87 ee 83 0c - */ -+/* 25 87 ee 83 09 << */ -+/* 25 87 ee 83 06 >> */ -+/* 25 87 ee 83 05 >" */ -+/* 25 87 ee 83 03 menu */ -+/* 26 00 00 00 00 for key repeat*/ -+ -+/* Thomas Glanzmann reports the following responses */ -+/* 25 87 ee ca 0b + */ -+/* 25 87 ee ca 0d - */ -+/* 25 87 ee ca 08 << */ -+/* 25 87 ee ca 07 >> */ -+/* 25 87 ee ca 04 >" */ -+/* 25 87 ee ca 02 menu */ -+/* 26 00 00 00 00 for key repeat*/ -+/* He also observes the following event sometimes */ -+/* sent after a key is release, which I interpret */ -+/* as a flat battery message */ -+/* 25 87 e0 ca 06 flat battery */ -+ -+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */ -+/* 25 87 ee 47 0b + */ -+/* 25 87 ee 47 0d - */ -+/* 25 87 ee 47 08 << */ -+/* 25 87 ee 47 07 >> */ -+/* 25 87 ee 47 04 >" */ -+/* 25 87 ee 47 02 menu */ -+/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */ -+ -+/* Bastien Nocera's "new" remote */ -+/* 25 87 ee 91 5f followed by -+ * 25 87 ee 91 05 gives you >" -+ * -+ * 25 87 ee 91 5c followed by -+ * 25 87 ee 91 05 gives you the middle button */ -+ -+static const unsigned short appleir_key_table[] = { -+ KEY_RESERVED, -+ KEY_MENU, -+ KEY_PLAYPAUSE, -+ KEY_FORWARD, -+ KEY_BACK, -+ KEY_VOLUMEUP, -+ KEY_VOLUMEDOWN, -+ KEY_ENTER, -+ KEY_RESERVED, -+}; -+ -+struct appleir { -+ struct input_dev *input_dev; -+ unsigned short keymap[ARRAY_SIZE(appleir_key_table)]; -+ u8 *data; -+ dma_addr_t dma_buf; -+ struct usb_device *usbdev; -+ unsigned int flags; -+ struct urb *urb; -+ struct timer_list key_up_timer; -+ int current_key; -+ int prev_key_idx; -+ char phys[32]; -+}; -+ -+static DEFINE_MUTEX(appleir_mutex); -+ -+enum { -+ APPLEIR_OPENED = 0x1, -+ APPLEIR_SUSPENDED = 0x2, -+}; -+ -+static struct usb_device_id appleir_ids[] = { -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(usb, appleir_ids); -+ -+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len) -+{ -+ int i; -+ -+ printk(KERN_ERR "appleir: %s (%d bytes)", msg, len); -+ -+ for (i = 0; i < len; ++i) -+ printk(" %02x", data[i]); -+ printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK); -+} -+ -+static int get_key(int data) -+{ -+ switch (data) { -+ case 0x02: -+ case 0x03: -+ /* menu */ -+ return 1; -+ case 0x04: -+ case 0x05: -+ /* >" */ -+ return 2; -+ case 0x06: -+ case 0x07: -+ /* >> */ -+ return 3; -+ case 0x08: -+ case 0x09: -+ /* << */ -+ return 4; -+ case 0x0a: -+ case 0x0b: -+ /* + */ -+ return 5; -+ case 0x0c: -+ case 0x0d: -+ /* - */ -+ return 6; -+ case 0x5c: -+ /* Middle button, on newer remotes, -+ * part of a 2 packet-command */ -+ return -7; -+ default: -+ return -1; -+ } -+} -+ -+static void key_up(struct appleir *appleir, int key) -+{ -+ dbginfo(&appleir->input_dev->dev, "key %d up\n", key); -+ input_report_key(appleir->input_dev, key, 0); -+ input_sync(appleir->input_dev); -+} -+ -+static void key_down(struct appleir *appleir, int key) -+{ -+ dbginfo(&appleir->input_dev->dev, "key %d down\n", key); -+ input_report_key(appleir->input_dev, key, 1); -+ input_sync(appleir->input_dev); -+} -+ -+static void battery_flat(struct appleir *appleir) -+{ -+ dev_err(&appleir->input_dev->dev, "possible flat battery?\n"); -+} -+ -+static void key_up_tick(unsigned long data) -+{ -+ struct appleir *appleir = (struct appleir *)data; -+ -+ if (appleir->current_key) { -+ key_up(appleir, appleir->current_key); -+ appleir->current_key = 0; -+ } -+} -+ -+static void new_data(struct appleir *appleir, u8 *data, int len) -+{ -+ static const u8 keydown[] = { 0x25, 0x87, 0xee }; -+ static const u8 keyrepeat[] = { 0x26, }; -+ static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 }; -+ -+ if (debug) -+ dump_packet(appleir, "received", data, len); -+ -+ if (len != 5) -+ return; -+ -+ if (!memcmp(data, keydown, sizeof(keydown))) { -+ int index; -+ -+ /* If we already have a key down, take it up before marking -+ this one down */ -+ if (appleir->current_key) -+ key_up(appleir, appleir->current_key); -+ -+ /* Handle dual packet commands */ -+ if (appleir->prev_key_idx > 0) -+ index = appleir->prev_key_idx; -+ else -+ index = get_key(data[4]); -+ -+ if (index > 0) { -+ appleir->current_key = appleir->keymap[index]; -+ -+ key_down(appleir, appleir->current_key); -+ /* Remote doesn't do key up, either pull them up, in the test -+ above, or here set a timer which pulls them up after 1/8 s */ -+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); -+ appleir->prev_key_idx = 0; -+ return; -+ } else if (index == -7) { -+ /* Remember key for next packet */ -+ appleir->prev_key_idx = 0 - index; -+ return; -+ } -+ } -+ -+ appleir->prev_key_idx = 0; -+ -+ if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) { -+ key_down(appleir, appleir->current_key); -+ /* Remote doesn't do key up, either pull them up, in the test -+ above, or here set a timer which pulls them up after 1/8 s */ -+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); -+ return; -+ } -+ -+ if (!memcmp(data, flatbattery, sizeof(flatbattery))) { -+ battery_flat(appleir); -+ /* Fall through */ -+ } -+ -+ dump_packet(appleir, "unknown packet", data, len); -+} -+ -+static void appleir_urb(struct urb *urb) -+{ -+ struct appleir *appleir = urb->context; -+ int status = urb->status; -+ int retval; -+ -+ switch (status) { -+ case 0: -+ new_data(appleir, urb->transfer_buffer, urb->actual_length); -+ break; -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ /* This urb is terminated, clean up */ -+ dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__, -+ urb->status); -+ return; -+ default: -+ dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__, -+ urb->status); -+ } -+ -+ retval = usb_submit_urb(urb, GFP_ATOMIC); -+ if (retval) -+ err("%s - usb_submit_urb failed with result %d", __func__, -+ retval); -+} -+ -+static int appleir_open(struct input_dev *dev) -+{ -+ struct appleir *appleir = input_get_drvdata(dev); -+ struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0); -+ int r; -+ -+ r = usb_autopm_get_interface(intf); -+ if (r) { -+ dev_err(&intf->dev, -+ "%s(): usb_autopm_get_interface() = %d\n", __func__, r); -+ return r; -+ } -+ -+ mutex_lock(&appleir_mutex); -+ -+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) { -+ r = -EIO; -+ goto fail; -+ } -+ -+ appleir->flags |= APPLEIR_OPENED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ usb_autopm_put_interface(intf); -+ -+ return 0; -+fail: -+ mutex_unlock(&appleir_mutex); -+ usb_autopm_put_interface(intf); -+ return r; -+} -+ -+static void appleir_close(struct input_dev *dev) -+{ -+ struct appleir *appleir = input_get_drvdata(dev); -+ -+ mutex_lock(&appleir_mutex); -+ -+ if (!(appleir->flags & APPLEIR_SUSPENDED)) { -+ usb_kill_urb(appleir->urb); -+ del_timer_sync(&appleir->key_up_timer); -+ } -+ -+ appleir->flags &= ~APPLEIR_OPENED; -+ -+ mutex_unlock(&appleir_mutex); -+} -+ -+static int appleir_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_endpoint_descriptor *endpoint; -+ struct appleir *appleir = NULL; -+ struct input_dev *input_dev; -+ int retval = -ENOMEM; -+ int i; -+ -+ appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL); -+ if (!appleir) -+ goto allocfail; -+ -+ appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL, -+ &appleir->dma_buf); -+ if (!appleir->data) -+ goto usbfail; -+ -+ appleir->urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!appleir->urb) -+ goto urbfail; -+ -+ appleir->usbdev = dev; -+ -+ input_dev = input_allocate_device(); -+ if (!input_dev) -+ goto inputfail; -+ -+ appleir->input_dev = input_dev; -+ -+ usb_make_path(dev, appleir->phys, sizeof(appleir->phys)); -+ strlcpy(appleir->phys, "/input0", sizeof(appleir->phys)); -+ -+ input_dev->name = "Apple Infrared Remote Controller"; -+ input_dev->phys = appleir->phys; -+ usb_to_input_id(dev, &input_dev->id); -+ input_dev->dev.parent = &intf->dev; -+ input_dev->keycode = appleir->keymap; -+ input_dev->keycodesize = sizeof(unsigned short); -+ input_dev->keycodemax = ARRAY_SIZE(appleir->keymap); -+ -+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); -+ -+ memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap)); -+ for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) -+ set_bit(appleir->keymap[i], input_dev->keybit); -+ clear_bit(KEY_RESERVED, input_dev->keybit); -+ -+ input_set_drvdata(input_dev, appleir); -+ input_dev->open = appleir_open; -+ input_dev->close = appleir_close; -+ -+ endpoint = &intf->cur_altsetting->endpoint[0].desc; -+ -+ usb_fill_int_urb(appleir->urb, dev, -+ usb_rcvintpipe(dev, endpoint->bEndpointAddress), -+ appleir->data, 8, -+ appleir_urb, appleir, endpoint->bInterval); -+ -+ appleir->urb->transfer_dma = appleir->dma_buf; -+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ setup_timer(&appleir->key_up_timer, -+ key_up_tick, (unsigned long) appleir); -+ -+ retval = input_register_device(appleir->input_dev); -+ if (retval) -+ goto inputfail; -+ -+ usb_set_intfdata(intf, appleir); -+ -+ return 0; -+ -+inputfail: -+ input_free_device(appleir->input_dev); -+ -+urbfail: -+ usb_free_urb(appleir->urb); -+ -+usbfail: -+ usb_free_coherent(dev, URB_SIZE, appleir->data, -+ appleir->dma_buf); -+ -+allocfail: -+ kfree(appleir); -+ -+ return retval; -+} -+ -+static void appleir_disconnect(struct usb_interface *intf) -+{ -+ struct appleir *appleir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ input_unregister_device(appleir->input_dev); -+ usb_free_urb(appleir->urb); -+ usb_free_coherent(interface_to_usbdev(intf), URB_SIZE, -+ appleir->data, appleir->dma_buf); -+ kfree(appleir); -+} -+ -+static int appleir_suspend(struct usb_interface *interface, -+ pm_message_t message) -+{ -+ struct appleir *appleir = usb_get_intfdata(interface); -+ -+ mutex_lock(&appleir_mutex); -+ if (appleir->flags & APPLEIR_OPENED) -+ usb_kill_urb(appleir->urb); -+ -+ appleir->flags |= APPLEIR_SUSPENDED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ return 0; -+} -+ -+static int appleir_resume(struct usb_interface *interface) -+{ -+ struct appleir *appleir; -+ int r = 0; -+ -+ appleir = usb_get_intfdata(interface); -+ -+ mutex_lock(&appleir_mutex); -+ if (appleir->flags & APPLEIR_OPENED) { -+ struct usb_endpoint_descriptor *endpoint; -+ -+ endpoint = &interface->cur_altsetting->endpoint[0].desc; -+ usb_fill_int_urb(appleir->urb, appleir->usbdev, -+ usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress), -+ appleir->data, 8, -+ appleir_urb, appleir, endpoint->bInterval); -+ appleir->urb->transfer_dma = appleir->dma_buf; -+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ /* And reset the USB device */ -+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) -+ r = -EIO; -+ } -+ -+ appleir->flags &= ~APPLEIR_SUSPENDED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ return r; -+} -+ -+static struct usb_driver appleir_driver = { -+ .name = "appleir", -+ .probe = appleir_probe, -+ .disconnect = appleir_disconnect, -+ .suspend = appleir_suspend, -+ .resume = appleir_resume, -+ .reset_resume = appleir_resume, -+ .id_table = appleir_ids, -+}; -+ -+static int __init appleir_init(void) -+{ -+ return usb_register(&appleir_driver); -+} -+ -+static void __exit appleir_exit(void) -+{ -+ usb_deregister(&appleir_driver); -+} -+ -+module_init(appleir_init); -+module_exit(appleir_exit); --- -1.7.2.2 - diff --git a/aoe-remove-extra-bdi_init.patch b/aoe-remove-extra-bdi_init.patch new file mode 100644 index 000000000..7275d5343 --- /dev/null +++ b/aoe-remove-extra-bdi_init.patch @@ -0,0 +1,78 @@ +Lines: 75 + +On Thu, Jan 03, 2013 at 12:15:35PM -0600, Ed Cashin wrote: +... +> >>>>> On Jan 3, 2013, at 8:25 AM, Josh Boyer wrote: +... +> >>>>>> [699170.611997] aoe: AoE v47 initialised. +... +> >>>>>> [699231.308319] WARNING: at lib/list_debug.c:62 __list_del_entry+0x82/0xd0() +> >>>>>> [699231.312031] Hardware name: S5000VSA +> >>>>>> [699231.315658] list_del corruption. next->prev should be ffff880009fa37e8, but was ffffffff81c79c00 +> >>>>>> [699231.319352] Modules linked in: aoe(-) ip6table_filter ip6_tables ebtable_nat ebtables lockd sunrpc bridge 8021q garp stp llc vfat fat binfmt_misc iTCO_wdt iTCO_vendor_support vhost_net lpc_ich radeon tun macvtap mfd_core serio_raw coretemp i2c_algo_bit ttm i5000_edac macvlan drm_kms_helper e1000e edac_core microcode i5k_amb shpchp i2c_i801 drm kvm_intel i2c_core kvm ioatdma dca raid1 +> >>>>>> [699231.336259] Pid: 8584, comm: modprobe Not tainted 3.6.11-1.fc17.x86_64 #1 +> >>>>>> [699231.340561] Call Trace: +> >>>>>> [699231.344865] [] warn_slowpath_common+0x7f/0xc0 +> >>>>>> [699231.349212] [] warn_slowpath_fmt+0x46/0x50 +> >>>>>> [699231.353595] [] __list_del_entry+0x82/0xd0 +> >>>>>> [699231.357954] [] list_del+0x11/0x40 +> >>>>>> [699231.362319] [] percpu_counter_destroy+0x28/0x50 +> >>>>>> [699231.366712] [] bdi_destroy+0x43/0x140 +> >>>>>> [699231.371127] [] blk_release_queue+0x8c/0xc0 +> >>>>>> [699231.375454] [] kobject_cleanup+0x82/0x1b0 +> >>>>>> [699231.379675] [] kobject_put+0x2b/0x60 +> >>>>>> [699231.383851] [] blk_put_queue+0x15/0x20 +> >>>>>> [699231.387899] [] blk_cleanup_queue+0xc9/0xe0 +> >>>>>> [699231.391794] [] aoedev_freedev+0x135/0x150 [aoe] +> >>>>>> [699231.395668] [] aoedev_exit+0x65/0x80 [aoe] +> >>>>>> [699231.399493] [] aoe_exit+0x2e/0x40 [aoe] +> >>>>>> [699231.403273] [] sys_delete_module+0x16e/0x2d0 +> >>>>>> [699231.407119] [] ? __schedule+0x3c6/0x7a0 +> >>>>>> [699231.411050] [] ? sys_write+0x4a/0x90 +> >>>>>> [699231.415033] [] system_call_fastpath+0x16/0x1b +> >>>>>> [699231.419117] ---[ end trace 9e1558af1964b569 ]--- +> >>>>>> [699231.423248] ------------[ cut here ]------------ + +The blk_alloc_queue has already done a bdi_init, so do not bdi_init again in +aoeblk_gdalloc. + +The patch below applies to v3.5.6, with its v47 aoe driver. On my system it +eliminates the list_del corruption messages. + +It updates VERSION for convenience during testing. + +diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h +index db195ab..2ccb9e2 100644 +--- a/drivers/block/aoe/aoe.h ++++ b/drivers/block/aoe/aoe.h +@@ -1,5 +1,5 @@ + /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +-#define VERSION "47" ++#define VERSION "47nobdi1" + #define AOE_MAJOR 152 + #define DEVICE_NAME "aoe" + +diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c +index 321de7b..7eca463 100644 +--- a/drivers/block/aoe/aoeblk.c ++++ b/drivers/block/aoe/aoeblk.c +@@ -276,8 +276,6 @@ aoeblk_gdalloc(void *vp) + goto err_mempool; + blk_queue_make_request(d->blkq, aoeblk_make_request); + d->blkq->backing_dev_info.name = "aoe"; +- if (bdi_init(&d->blkq->backing_dev_info)) +- goto err_blkq; + spin_lock_irqsave(&d->lock, flags); + gd->major = AOE_MAJOR; + gd->first_minor = d->sysminor * AOE_PARTITIONS; +@@ -298,9 +296,6 @@ aoeblk_gdalloc(void *vp) + aoedisk_add_sysfs(d); + return; + +-err_blkq: +- blk_cleanup_queue(d->blkq); +- d->blkq = NULL; + err_mempool: + mempool_destroy(d->bufpool); + err_disk: + diff --git a/benet-remove-bogus-unlikely-on-vlan-check.patch b/benet-remove-bogus-unlikely-on-vlan-check.patch new file mode 100644 index 000000000..08c00817e --- /dev/null +++ b/benet-remove-bogus-unlikely-on-vlan-check.patch @@ -0,0 +1,39 @@ +From 82f15998fafe683add83f7a11b2e25f919b3cd2d Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Tue, 25 Oct 2011 13:47:16 -0400 +Subject: [PATCH] benet: remove bogus "unlikely" on vlan check + +Use of unlikely in this place is wrong. Remove it. + +Signed-off-by: Jiri Pirko +Signed-off-by: David S. Miller +Backported-by: Josh Boyer +--- + drivers/net/benet/be_main.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c +index c411bb1..6df0c7e 100644 +--- a/drivers/net/benet/be_main.c ++++ b/drivers/net/benet/be_main.c +@@ -1192,7 +1192,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, + skb->rxhash = rxcp->rss_hash; + + +- if (unlikely(rxcp->vlanf)) ++ if (rxcp->vlanf) + __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag); + + netif_receive_skb(skb); +@@ -1249,7 +1249,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + +- if (unlikely(rxcp->vlanf)) ++ if (rxcp->vlanf) + __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag); + + napi_gro_frags(&eq_obj->napi); +-- +1.7.6.4 + diff --git a/block-fix-a-crash-when-block-device-is.patch b/block-fix-a-crash-when-block-device-is.patch new file mode 100644 index 000000000..af992830e --- /dev/null +++ b/block-fix-a-crash-when-block-device-is.patch @@ -0,0 +1,214 @@ +Fix a crash when block device is read and block size is changed at the same time + +commit b87570f5d349661814b262dd5fc40787700f80d6 +Author: Mikulas Patocka +Date: Wed Sep 26 07:46:40 2012 +0200 + + Fix a crash when block device is read and block size is changed at the same time + + The kernel may crash when block size is changed and I/O is issued + simultaneously. + + Because some subsystems (udev or lvm) may read any block device anytime, + the bug actually puts any code that changes a block device size in + jeopardy. + + The crash can be reproduced if you place "msleep(1000)" to + blkdev_get_blocks just before "bh->b_size = max_blocks << + inode->i_blkbits;". + Then, run "dd if=/dev/ram0 of=/dev/null bs=4k count=1 iflag=direct" + While it is waiting in msleep, run "blockdev --setbsz 2048 /dev/ram0" + You get a BUG. + + The direct and non-direct I/O is written with the assumption that block + size does not change. It doesn't seem practical to fix these crashes + one-by-one there may be many crash possibilities when block size changes + at a certain place and it is impossible to find them all and verify the + code. + + This patch introduces a new rw-lock bd_block_size_semaphore. The lock is + taken for read during I/O. It is taken for write when changing block + size. Consequently, block size can't be changed while I/O is being + submitted. + + For asynchronous I/O, the patch only prevents block size change while + the I/O is being submitted. The block size can change when the I/O is in + progress or when the I/O is being finished. This is acceptable because + there are no accesses to block size when asynchronous I/O is being + finished. + + The patch prevents block size changing while the device is mapped with + mmap. + + Signed-off-by: Mikulas Patocka + Signed-off-by: Jens Axboe + +Index: linux-3.6.x86_64/drivers/char/raw.c +=================================================================== +--- linux-3.6.x86_64.orig/drivers/char/raw.c 2012-11-16 17:12:35.127010280 -0500 ++++ linux-3.6.x86_64/drivers/char/raw.c 2012-11-16 17:12:37.381002516 -0500 +@@ -285,7 +285,7 @@ + + static const struct file_operations raw_fops = { + .read = do_sync_read, +- .aio_read = generic_file_aio_read, ++ .aio_read = blkdev_aio_read, + .write = do_sync_write, + .aio_write = blkdev_aio_write, + .fsync = blkdev_fsync, +Index: linux-3.6.x86_64/fs/block_dev.c +=================================================================== +--- linux-3.6.x86_64.orig/fs/block_dev.c 2012-11-16 17:12:35.127010280 -0500 ++++ linux-3.6.x86_64/fs/block_dev.c 2012-11-16 17:12:37.381002516 -0500 +@@ -116,6 +116,8 @@ + + int set_blocksize(struct block_device *bdev, int size) + { ++ struct address_space *mapping; ++ + /* Size must be a power of two, and between 512 and PAGE_SIZE */ + if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) + return -EINVAL; +@@ -124,6 +126,20 @@ + if (size < bdev_logical_block_size(bdev)) + return -EINVAL; + ++ /* Prevent starting I/O or mapping the device */ ++ down_write(&bdev->bd_block_size_semaphore); ++ ++ /* Check that the block device is not memory mapped */ ++ mapping = bdev->bd_inode->i_mapping; ++ mutex_lock(&mapping->i_mmap_mutex); ++ if (!prio_tree_empty(&mapping->i_mmap) || ++ !list_empty(&mapping->i_mmap_nonlinear)) { ++ mutex_unlock(&mapping->i_mmap_mutex); ++ up_write(&bdev->bd_block_size_semaphore); ++ return -EBUSY; ++ } ++ mutex_unlock(&mapping->i_mmap_mutex); ++ + /* Don't change the size if it is same as current */ + if (bdev->bd_block_size != size) { + sync_blockdev(bdev); +@@ -131,6 +147,9 @@ + bdev->bd_inode->i_blkbits = blksize_bits(size); + kill_bdev(bdev); + } ++ ++ up_write(&bdev->bd_block_size_semaphore); ++ + return 0; + } + +@@ -472,6 +491,7 @@ + inode_init_once(&ei->vfs_inode); + /* Initialize mutex for freeze. */ + mutex_init(&bdev->bd_fsfreeze_mutex); ++ init_rwsem(&bdev->bd_block_size_semaphore); + } + + static inline void __bd_forget(struct inode *inode) +@@ -1567,6 +1587,22 @@ + return blkdev_ioctl(bdev, mode, cmd, arg); + } + ++ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t pos) ++{ ++ ssize_t ret; ++ struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host); ++ ++ down_read(&bdev->bd_block_size_semaphore); ++ ++ ret = generic_file_aio_read(iocb, iov, nr_segs, pos); ++ ++ up_read(&bdev->bd_block_size_semaphore); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(blkdev_aio_read); ++ + /* + * Write data to the block device. Only intended for the block device itself + * and the raw driver which basically is a fake block device. +@@ -1578,12 +1614,16 @@ + unsigned long nr_segs, loff_t pos) + { + struct file *file = iocb->ki_filp; ++ struct block_device *bdev = I_BDEV(file->f_mapping->host); + struct blk_plug plug; + ssize_t ret; + + BUG_ON(iocb->ki_pos != pos); + + blk_start_plug(&plug); ++ ++ down_read(&bdev->bd_block_size_semaphore); ++ + ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); + if (ret > 0 || ret == -EIOCBQUEUED) { + ssize_t err; +@@ -1592,11 +1632,29 @@ + if (err < 0 && ret > 0) + ret = err; + } ++ ++ up_read(&bdev->bd_block_size_semaphore); ++ + blk_finish_plug(&plug); ++ + return ret; + } + EXPORT_SYMBOL_GPL(blkdev_aio_write); + ++int blkdev_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int ret; ++ struct block_device *bdev = I_BDEV(file->f_mapping->host); ++ ++ down_read(&bdev->bd_block_size_semaphore); ++ ++ ret = generic_file_mmap(file, vma); ++ ++ up_read(&bdev->bd_block_size_semaphore); ++ ++ return ret; ++} ++ + /* + * Try to release a page associated with block device when the system + * is under memory pressure. +@@ -1627,9 +1685,9 @@ + .llseek = block_llseek, + .read = do_sync_read, + .write = do_sync_write, +- .aio_read = generic_file_aio_read, ++ .aio_read = blkdev_aio_read, + .aio_write = blkdev_aio_write, +- .mmap = generic_file_mmap, ++ .mmap = blkdev_mmap, + .fsync = blkdev_fsync, + .unlocked_ioctl = block_ioctl, + #ifdef CONFIG_COMPAT +Index: linux-3.6.x86_64/include/linux/fs.h +=================================================================== +--- linux-3.6.x86_64.orig/include/linux/fs.h 2012-11-16 17:12:35.127010280 -0500 ++++ linux-3.6.x86_64/include/linux/fs.h 2012-11-16 17:12:37.424002387 -0500 +@@ -724,6 +724,8 @@ + int bd_fsfreeze_count; + /* Mutex for freeze */ + struct mutex bd_fsfreeze_mutex; ++ /* A semaphore that prevents I/O while block size is being changed */ ++ struct rw_semaphore bd_block_size_semaphore; + }; + + /* +@@ -2564,6 +2566,8 @@ + unsigned long *nr_segs, size_t *count, int access_flags); + + /* fs/block_dev.c */ ++extern ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t pos); + extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); + extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, diff --git a/blockdev-turn-a-rw-semaphore-into-a-percpu-rw-sem.patch b/blockdev-turn-a-rw-semaphore-into-a-percpu-rw-sem.patch new file mode 100644 index 000000000..82caa6b76 --- /dev/null +++ b/blockdev-turn-a-rw-semaphore-into-a-percpu-rw-sem.patch @@ -0,0 +1,290 @@ +blockdev: turn a rw semaphore into a percpu rw semaphore + +commit 62ac665ff9fc07497ca524bd20d6a96893d11071 +Author: Mikulas Patocka +Date: Wed Sep 26 07:46:43 2012 +0200 + + blockdev: turn a rw semaphore into a percpu rw semaphore + + This avoids cache line bouncing when many processes lock the semaphore + for read. + + New percpu lock implementation + + The lock consists of an array of percpu unsigned integers, a boolean + variable and a mutex. + + When we take the lock for read, we enter rcu read section, check for a + "locked" variable. If it is false, we increase a percpu counter on the + current cpu and exit the rcu section. If "locked" is true, we exit the + rcu section, take the mutex and drop it (this waits until a writer + finished) and retry. + + Unlocking for read just decreases percpu variable. Note that we can + unlock on a difference cpu than where we locked, in this case the + counter underflows. The sum of all percpu counters represents the number + of processes that hold the lock for read. + + When we need to lock for write, we take the mutex, set "locked" variable + to true and synchronize rcu. Since RCU has been synchronized, no + processes can create new read locks. We wait until the sum of percpu + counters is zero - when it is, there are no readers in the critical + section. + + Signed-off-by: Mikulas Patocka + Signed-off-by: Jens Axboe + +Index: linux-3.6.x86_64/Documentation/percpu-rw-semaphore.txt +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-3.6.x86_64/Documentation/percpu-rw-semaphore.txt 2012-11-16 17:12:57.351936583 -0500 +@@ -0,0 +1,27 @@ ++Percpu rw semaphores ++-------------------- ++ ++Percpu rw semaphores is a new read-write semaphore design that is ++optimized for locking for reading. ++ ++The problem with traditional read-write semaphores is that when multiple ++cores take the lock for reading, the cache line containing the semaphore ++is bouncing between L1 caches of the cores, causing performance ++degradation. ++ ++Locking for reading it very fast, it uses RCU and it avoids any atomic ++instruction in the lock and unlock path. On the other hand, locking for ++writing is very expensive, it calls synchronize_rcu() that can take ++hundreds of microseconds. ++ ++The lock is declared with "struct percpu_rw_semaphore" type. ++The lock is initialized percpu_init_rwsem, it returns 0 on success and ++-ENOMEM on allocation failure. ++The lock must be freed with percpu_free_rwsem to avoid memory leak. ++ ++The lock is locked for read with percpu_down_read, percpu_up_read and ++for write with percpu_down_write, percpu_up_write. ++ ++The idea of using RCU for optimized rw-lock was introduced by ++Eric Dumazet . ++The code was written by Mikulas Patocka +Index: linux-3.6.x86_64/fs/block_dev.c +=================================================================== +--- linux-3.6.x86_64.orig/fs/block_dev.c 2012-11-16 17:12:37.381002516 -0500 ++++ linux-3.6.x86_64/fs/block_dev.c 2012-11-16 17:27:41.217005828 -0500 +@@ -127,7 +127,7 @@ + return -EINVAL; + + /* Prevent starting I/O or mapping the device */ +- down_write(&bdev->bd_block_size_semaphore); ++ percpu_down_write(&bdev->bd_block_size_semaphore); + + /* Check that the block device is not memory mapped */ + mapping = bdev->bd_inode->i_mapping; +@@ -135,7 +135,7 @@ + if (!prio_tree_empty(&mapping->i_mmap) || + !list_empty(&mapping->i_mmap_nonlinear)) { + mutex_unlock(&mapping->i_mmap_mutex); +- up_write(&bdev->bd_block_size_semaphore); ++ percpu_up_write(&bdev->bd_block_size_semaphore); + return -EBUSY; + } + mutex_unlock(&mapping->i_mmap_mutex); +@@ -148,7 +148,7 @@ + kill_bdev(bdev); + } + +- up_write(&bdev->bd_block_size_semaphore); ++ percpu_up_write(&bdev->bd_block_size_semaphore); + + return 0; + } +@@ -460,6 +460,12 @@ + struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL); + if (!ei) + return NULL; ++ ++ if (unlikely(percpu_init_rwsem(&ei->bdev.bd_block_size_semaphore))) { ++ kmem_cache_free(bdev_cachep, ei); ++ return NULL; ++ } ++ + return &ei->vfs_inode; + } + +@@ -468,6 +474,8 @@ + struct inode *inode = container_of(head, struct inode, i_rcu); + struct bdev_inode *bdi = BDEV_I(inode); + ++ percpu_free_rwsem(&bdi->bdev.bd_block_size_semaphore); ++ + kmem_cache_free(bdev_cachep, bdi); + } + +@@ -491,7 +499,6 @@ + inode_init_once(&ei->vfs_inode); + /* Initialize mutex for freeze. */ + mutex_init(&bdev->bd_fsfreeze_mutex); +- init_rwsem(&bdev->bd_block_size_semaphore); + } + + static inline void __bd_forget(struct inode *inode) +@@ -1593,11 +1600,11 @@ + ssize_t ret; + struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host); + +- down_read(&bdev->bd_block_size_semaphore); ++ percpu_down_read(&bdev->bd_block_size_semaphore); + + ret = generic_file_aio_read(iocb, iov, nr_segs, pos); + +- up_read(&bdev->bd_block_size_semaphore); ++ percpu_up_read(&bdev->bd_block_size_semaphore); + + return ret; + } +@@ -1622,7 +1629,7 @@ + + blk_start_plug(&plug); + +- down_read(&bdev->bd_block_size_semaphore); ++ percpu_down_read(&bdev->bd_block_size_semaphore); + + ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); + if (ret > 0 || ret == -EIOCBQUEUED) { +@@ -1633,7 +1640,7 @@ + ret = err; + } + +- up_read(&bdev->bd_block_size_semaphore); ++ percpu_up_read(&bdev->bd_block_size_semaphore); + + blk_finish_plug(&plug); + +@@ -1646,11 +1653,11 @@ + int ret; + struct block_device *bdev = I_BDEV(file->f_mapping->host); + +- down_read(&bdev->bd_block_size_semaphore); ++ percpu_down_read(&bdev->bd_block_size_semaphore); + + ret = generic_file_mmap(file, vma); + +- up_read(&bdev->bd_block_size_semaphore); ++ percpu_up_read(&bdev->bd_block_size_semaphore); + + return ret; + } +Index: linux-3.6.x86_64/include/linux/fs.h +=================================================================== +--- linux-3.6.x86_64.orig/include/linux/fs.h 2012-11-16 17:12:37.424002387 -0500 ++++ linux-3.6.x86_64/include/linux/fs.h 2012-11-16 17:28:12.578901349 -0500 +@@ -415,6 +415,7 @@ + #include + #include + #include ++#include + + #include + +@@ -725,7 +726,7 @@ + /* Mutex for freeze */ + struct mutex bd_fsfreeze_mutex; + /* A semaphore that prevents I/O while block size is being changed */ +- struct rw_semaphore bd_block_size_semaphore; ++ struct percpu_rw_semaphore bd_block_size_semaphore; + }; + + /* +Index: linux-3.6.x86_64/include/linux/percpu-rwsem.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-3.6.x86_64/include/linux/percpu-rwsem.h 2012-11-16 17:12:57.354936574 -0500 +@@ -0,0 +1,89 @@ ++#ifndef _LINUX_PERCPU_RWSEM_H ++#define _LINUX_PERCPU_RWSEM_H ++ ++#include ++#include ++#include ++#include ++ ++struct percpu_rw_semaphore { ++ unsigned __percpu *counters; ++ bool locked; ++ struct mutex mtx; ++}; ++ ++static inline void percpu_down_read(struct percpu_rw_semaphore *p) ++{ ++ rcu_read_lock(); ++ if (unlikely(p->locked)) { ++ rcu_read_unlock(); ++ mutex_lock(&p->mtx); ++ this_cpu_inc(*p->counters); ++ mutex_unlock(&p->mtx); ++ return; ++ } ++ this_cpu_inc(*p->counters); ++ rcu_read_unlock(); ++} ++ ++static inline void percpu_up_read(struct percpu_rw_semaphore *p) ++{ ++ /* ++ * On X86, write operation in this_cpu_dec serves as a memory unlock ++ * barrier (i.e. memory accesses may be moved before the write, but ++ * no memory accesses are moved past the write). ++ * On other architectures this may not be the case, so we need smp_mb() ++ * there. ++ */ ++#if defined(CONFIG_X86) && (!defined(CONFIG_X86_PPRO_FENCE) && !defined(CONFIG_X86_OOSTORE)) ++ barrier(); ++#else ++ smp_mb(); ++#endif ++ this_cpu_dec(*p->counters); ++} ++ ++static inline unsigned __percpu_count(unsigned __percpu *counters) ++{ ++ unsigned total = 0; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) ++ total += ACCESS_ONCE(*per_cpu_ptr(counters, cpu)); ++ ++ return total; ++} ++ ++static inline void percpu_down_write(struct percpu_rw_semaphore *p) ++{ ++ mutex_lock(&p->mtx); ++ p->locked = true; ++ synchronize_rcu(); ++ while (__percpu_count(p->counters)) ++ msleep(1); ++ smp_rmb(); /* paired with smp_mb() in percpu_sem_up_read() */ ++} ++ ++static inline void percpu_up_write(struct percpu_rw_semaphore *p) ++{ ++ p->locked = false; ++ mutex_unlock(&p->mtx); ++} ++ ++static inline int percpu_init_rwsem(struct percpu_rw_semaphore *p) ++{ ++ p->counters = alloc_percpu(unsigned); ++ if (unlikely(!p->counters)) ++ return -ENOMEM; ++ p->locked = false; ++ mutex_init(&p->mtx); ++ return 0; ++} ++ ++static inline void percpu_free_rwsem(struct percpu_rw_semaphore *p) ++{ ++ free_percpu(p->counters); ++ p->counters = NULL; /* catch use after free bugs */ ++} ++ ++#endif diff --git a/brcm80211.patch b/brcm80211.patch new file mode 100644 index 000000000..7c6d42e76 --- /dev/null +++ b/brcm80211.patch @@ -0,0 +1,97238 @@ +This patch represents the state of the brcm80211 driver as of 3.2-rc2, +plus a couple of one-line changes required to make it build on a 3.1 +base kernel. + +Obviously, this patch should be dropped completely when rebasing to the +final 3.2 kernel from upstream. + +-- John W. Linville + +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h.orig 2011-11-09 13:46:58.225800883 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h 2011-11-09 13:47:16.977566455 -0500 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2011 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _bcmchip_h_ ++#define _bcmchip_h_ ++ ++/* bcm4329 */ ++/* SDIO device core, ID 0x829 */ ++#define BCM4329_CORE_BUS_BASE 0x18011000 ++/* internal memory core, ID 0x80e */ ++#define BCM4329_CORE_SOCRAM_BASE 0x18003000 ++/* ARM Cortex M3 core, ID 0x82a */ ++#define BCM4329_CORE_ARM_BASE 0x18002000 ++#define BCM4329_RAMSIZE 0x48000 ++/* firmware name */ ++#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin" ++#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt" ++ ++#endif /* _bcmchip_h_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c.orig 2011-11-09 13:46:58.226800871 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c 2011-11-09 13:47:16.978566442 -0500 +@@ -0,0 +1,371 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++/* ****************** SDIO CARD Interface Functions **************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include "dhd.h" ++#include "dhd_bus.h" ++#include "dhd_dbg.h" ++#include "sdio_host.h" ++ ++#define SDIOH_API_ACCESS_RETRY_LIMIT 2 ++ ++static void brcmf_sdioh_irqhandler(struct sdio_func *func) ++{ ++ struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); ++ ++ brcmf_dbg(TRACE, "***IRQHandler\n"); ++ ++ sdio_release_host(func); ++ ++ brcmf_sdbrcm_isr(sdiodev->bus); ++ ++ sdio_claim_host(func); ++} ++ ++int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev) ++{ ++ brcmf_dbg(TRACE, "Entering\n"); ++ ++ sdio_claim_host(sdiodev->func[1]); ++ sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler); ++ sdio_release_host(sdiodev->func[1]); ++ ++ return 0; ++} ++ ++int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev) ++{ ++ brcmf_dbg(TRACE, "Entering\n"); ++ ++ sdio_claim_host(sdiodev->func[1]); ++ sdio_release_irq(sdiodev->func[1]); ++ sdio_release_host(sdiodev->func[1]); ++ ++ return 0; ++} ++ ++u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, ++ int *err) ++{ ++ int status; ++ s32 retry = 0; ++ u8 data = 0; ++ ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ udelay(1000); ++ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num, ++ addr, (u8 *) &data); ++ } while (status != 0 ++ && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++ if (err) ++ *err = status; ++ ++ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", ++ fnc_num, addr, data); ++ ++ return data; ++} ++ ++void ++brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, ++ u8 data, int *err) ++{ ++ int status; ++ s32 retry = 0; ++ ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ udelay(1000); ++ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num, ++ addr, (u8 *) &data); ++ } while (status != 0 ++ && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++ if (err) ++ *err = status; ++ ++ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", ++ fnc_num, addr, data); ++} ++ ++int ++brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) ++{ ++ int err = 0; ++ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, ++ &err); ++ if (!err) ++ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, ++ &err); ++ ++ return err; ++} ++ ++u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size) ++{ ++ int status; ++ u32 word = 0; ++ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; ++ ++ brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr); ++ ++ if (bar0 != sdiodev->sbwad) { ++ if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0)) ++ return 0xFFFFFFFF; ++ ++ sdiodev->sbwad = bar0; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1, ++ addr, &word, size); ++ ++ sdiodev->regfail = (status != 0); ++ ++ brcmf_dbg(INFO, "u32data = 0x%x\n", word); ++ ++ /* if ok, return appropriately masked word */ ++ if (status == 0) { ++ switch (size) { ++ case sizeof(u8): ++ return word & 0xff; ++ case sizeof(u16): ++ return word & 0xffff; ++ case sizeof(u32): ++ return word; ++ default: ++ sdiodev->regfail = true; ++ ++ } ++ } ++ ++ /* otherwise, bad sdio access or invalid size */ ++ brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size); ++ return 0xFFFFFFFF; ++} ++ ++u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, ++ u32 data) ++{ ++ int status; ++ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; ++ int err = 0; ++ ++ brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", ++ addr, size * 8, data); ++ ++ if (bar0 != sdiodev->sbwad) { ++ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); ++ if (err) ++ return err; ++ ++ sdiodev->sbwad = bar0; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ status = ++ brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1, ++ addr, &data, size); ++ sdiodev->regfail = (status != 0); ++ ++ if (status == 0) ++ return 0; ++ ++ brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n", ++ data, addr, size); ++ return 0xFFFFFFFF; ++} ++ ++bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev) ++{ ++ return sdiodev->regfail; ++} ++ ++int ++brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, ++ uint flags, ++ u8 *buf, uint nbytes, struct sk_buff *pkt) ++{ ++ int status; ++ uint incr_fix; ++ uint width; ++ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; ++ int err = 0; ++ ++ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); ++ ++ /* Async not implemented yet */ ++ if (flags & SDIO_REQ_ASYNC) ++ return -ENOTSUPP; ++ ++ if (bar0 != sdiodev->sbwad) { ++ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); ++ if (err) ++ return err; ++ ++ sdiodev->sbwad = bar0; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, ++ fn, addr, width, nbytes, buf, pkt); ++ ++ return status; ++} ++ ++int ++brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, ++ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt) ++{ ++ uint incr_fix; ++ uint width; ++ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; ++ int err = 0; ++ ++ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); ++ ++ /* Async not implemented yet */ ++ if (flags & SDIO_REQ_ASYNC) ++ return -ENOTSUPP; ++ ++ if (bar0 != sdiodev->sbwad) { ++ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); ++ if (err) ++ return err; ++ ++ sdiodev->sbwad = bar0; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, ++ addr, width, nbytes, buf, pkt); ++} ++ ++int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, ++ u8 *buf, uint nbytes) ++{ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, ++ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, ++ addr, 4, nbytes, buf, NULL); ++} ++ ++int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) ++{ ++ char t_func = (char)fn; ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* issue abort cmd52 command through F0 */ ++ brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, ++ SDIO_CCCR_ABORT, &t_func); ++ ++ brcmf_dbg(TRACE, "Exit\n"); ++ return 0; ++} ++ ++int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) ++{ ++ u32 regs = 0; ++ int ret = 0; ++ ++ ret = brcmf_sdioh_attach(sdiodev); ++ if (ret) ++ goto out; ++ ++ regs = SI_ENUM_BASE; ++ ++ /* Report the BAR, to fix if needed */ ++ sdiodev->sbwad = SI_ENUM_BASE; ++ ++ /* try to attach to the target device */ ++ sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev); ++ if (!sdiodev->bus) { ++ brcmf_dbg(ERROR, "device attach failed\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++out: ++ if (ret) ++ brcmf_sdio_remove(sdiodev); ++ ++ return ret; ++} ++EXPORT_SYMBOL(brcmf_sdio_probe); ++ ++int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) ++{ ++ if (sdiodev->bus) { ++ brcmf_sdbrcm_disconnect(sdiodev->bus); ++ sdiodev->bus = NULL; ++ } ++ ++ brcmf_sdioh_detach(sdiodev); ++ ++ sdiodev->sbwad = 0; ++ ++ return 0; ++} ++EXPORT_SYMBOL(brcmf_sdio_remove); ++ ++void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable) ++{ ++ if (enable) ++ brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); ++ else ++ brcmf_sdbrcm_wd_timer(sdiodev->bus, 0); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c.orig 2011-11-09 13:46:58.228800847 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c 2011-11-09 13:47:16.980566416 -0500 +@@ -0,0 +1,626 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* request_irq() */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include "sdio_host.h" ++#include "dhd.h" ++#include "dhd_dbg.h" ++#include "wl_cfg80211.h" ++ ++#define SDIO_VENDOR_ID_BROADCOM 0x02d0 ++ ++#define DMA_ALIGN_MASK 0x03 ++ ++#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 ++ ++#define SDIO_FUNC1_BLOCKSIZE 64 ++#define SDIO_FUNC2_BLOCKSIZE 512 ++ ++/* devices we support, null terminated */ ++static const struct sdio_device_id brcmf_sdmmc_ids[] = { ++ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, ++ { /* end: all zeroes */ }, ++}; ++MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); ++ ++static bool ++brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) ++{ ++ bool is_err = false; ++#ifdef CONFIG_PM_SLEEP ++ is_err = atomic_read(&sdiodev->suspend); ++#endif ++ return is_err; ++} ++ ++static void ++brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq) ++{ ++#ifdef CONFIG_PM_SLEEP ++ int retry = 0; ++ while (atomic_read(&sdiodev->suspend) && retry++ != 30) ++ wait_event_timeout(*wq, false, HZ/100); ++#endif ++} ++ ++static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, ++ uint regaddr, u8 *byte) ++{ ++ struct sdio_func *sdfunc = sdiodev->func[0]; ++ int err_ret; ++ ++ /* ++ * Can only directly write to some F0 registers. ++ * Handle F2 enable/disable and Abort command ++ * as a special case. ++ */ ++ if (regaddr == SDIO_CCCR_IOEx) { ++ sdfunc = sdiodev->func[2]; ++ if (sdfunc) { ++ sdio_claim_host(sdfunc); ++ if (*byte & SDIO_FUNC_ENABLE_2) { ++ /* Enable Function 2 */ ++ err_ret = sdio_enable_func(sdfunc); ++ if (err_ret) ++ brcmf_dbg(ERROR, ++ "enable F2 failed:%d\n", ++ err_ret); ++ } else { ++ /* Disable Function 2 */ ++ err_ret = sdio_disable_func(sdfunc); ++ if (err_ret) ++ brcmf_dbg(ERROR, ++ "Disable F2 failed:%d\n", ++ err_ret); ++ } ++ sdio_release_host(sdfunc); ++ } ++ } else if (regaddr == SDIO_CCCR_ABORT) { ++ sdio_claim_host(sdfunc); ++ sdio_writeb(sdfunc, *byte, regaddr, &err_ret); ++ sdio_release_host(sdfunc); ++ } else if (regaddr < 0xF0) { ++ brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); ++ err_ret = -EPERM; ++ } else { ++ sdio_claim_host(sdfunc); ++ sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); ++ sdio_release_host(sdfunc); ++ } ++ ++ return err_ret; ++} ++ ++int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, ++ uint regaddr, u8 *byte) ++{ ++ int err_ret; ++ ++ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); ++ ++ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); ++ if (brcmf_pm_resume_error(sdiodev)) ++ return -EIO; ++ ++ if (rw && func == 0) { ++ /* handle F0 separately */ ++ err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); ++ } else { ++ sdio_claim_host(sdiodev->func[func]); ++ if (rw) /* CMD52 Write */ ++ sdio_writeb(sdiodev->func[func], *byte, regaddr, ++ &err_ret); ++ else if (func == 0) { ++ *byte = sdio_f0_readb(sdiodev->func[func], regaddr, ++ &err_ret); ++ } else { ++ *byte = sdio_readb(sdiodev->func[func], regaddr, ++ &err_ret); ++ } ++ sdio_release_host(sdiodev->func[func]); ++ } ++ ++ if (err_ret) ++ brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", ++ rw ? "write" : "read", func, regaddr, *byte, err_ret); ++ ++ return err_ret; ++} ++ ++int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, ++ uint rw, uint func, uint addr, u32 *word, ++ uint nbytes) ++{ ++ int err_ret = -EIO; ++ ++ if (func == 0) { ++ brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n"); ++ return -EINVAL; ++ } ++ ++ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", ++ rw, func, addr, nbytes); ++ ++ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); ++ if (brcmf_pm_resume_error(sdiodev)) ++ return -EIO; ++ /* Claim host controller */ ++ sdio_claim_host(sdiodev->func[func]); ++ ++ if (rw) { /* CMD52 Write */ ++ if (nbytes == 4) ++ sdio_writel(sdiodev->func[func], *word, addr, ++ &err_ret); ++ else if (nbytes == 2) ++ sdio_writew(sdiodev->func[func], (*word & 0xFFFF), ++ addr, &err_ret); ++ else ++ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); ++ } else { /* CMD52 Read */ ++ if (nbytes == 4) ++ *word = sdio_readl(sdiodev->func[func], addr, &err_ret); ++ else if (nbytes == 2) ++ *word = sdio_readw(sdiodev->func[func], addr, ++ &err_ret) & 0xFFFF; ++ else ++ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); ++ } ++ ++ /* Release host controller */ ++ sdio_release_host(sdiodev->func[func]); ++ ++ if (err_ret) ++ brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", ++ rw ? "write" : "read", err_ret); ++ ++ return err_ret; ++} ++ ++static int ++brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, ++ uint write, uint func, uint addr, ++ struct sk_buff *pkt) ++{ ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ u32 SGCount = 0; ++ int err_ret = 0; ++ ++ struct sk_buff *pnext; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); ++ if (brcmf_pm_resume_error(sdiodev)) ++ return -EIO; ++ ++ /* Claim host controller */ ++ sdio_claim_host(sdiodev->func[func]); ++ for (pnext = pkt; pnext; pnext = pnext->next) { ++ uint pkt_len = pnext->len; ++ pkt_len += 3; ++ pkt_len &= 0xFFFFFFFC; ++ ++ if ((write) && (!fifo)) { ++ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ++ ((u8 *) (pnext->data)), ++ pkt_len); ++ } else if (write) { ++ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ++ ((u8 *) (pnext->data)), ++ pkt_len); ++ } else if (fifo) { ++ err_ret = sdio_readsb(sdiodev->func[func], ++ ((u8 *) (pnext->data)), ++ addr, pkt_len); ++ } else { ++ err_ret = sdio_memcpy_fromio(sdiodev->func[func], ++ ((u8 *) (pnext->data)), ++ addr, pkt_len); ++ } ++ ++ if (err_ret) { ++ brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", ++ write ? "TX" : "RX", pnext, SGCount, addr, ++ pkt_len, err_ret); ++ } else { ++ brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", ++ write ? "TX" : "RX", pnext, SGCount, addr, ++ pkt_len); ++ } ++ ++ if (!fifo) ++ addr += pkt_len; ++ SGCount++; ++ ++ } ++ ++ /* Release host controller */ ++ sdio_release_host(sdiodev->func[func]); ++ ++ brcmf_dbg(TRACE, "Exit\n"); ++ return err_ret; ++} ++ ++/* ++ * This function takes a buffer or packet, and fixes everything up ++ * so that in the end, a DMA-able packet is created. ++ * ++ * A buffer does not have an associated packet pointer, ++ * and may or may not be aligned. ++ * A packet may consist of a single packet, or a packet chain. ++ * If it is a packet chain, then all the packets in the chain ++ * must be properly aligned. ++ * ++ * If the packet data is not aligned, then there may only be ++ * one packet, and in this case, it is copied to a new ++ * aligned packet. ++ * ++ */ ++int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, ++ uint fix_inc, uint write, uint func, uint addr, ++ uint reg_width, uint buflen_u, u8 *buffer, ++ struct sk_buff *pkt) ++{ ++ int Status; ++ struct sk_buff *mypkt = NULL; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); ++ if (brcmf_pm_resume_error(sdiodev)) ++ return -EIO; ++ /* Case 1: we don't have a packet. */ ++ if (pkt == NULL) { ++ brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n", ++ write ? "TX" : "RX", buflen_u); ++ mypkt = brcmu_pkt_buf_get_skb(buflen_u); ++ if (!mypkt) { ++ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", ++ buflen_u); ++ return -EIO; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) ++ memcpy(mypkt->data, buffer, buflen_u); ++ ++ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, ++ func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) ++ memcpy(buffer, mypkt->data, buflen_u); ++ ++ brcmu_pkt_buf_free_skb(mypkt); ++ } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { ++ /* ++ * Case 2: We have a packet, but it is unaligned. ++ * In this case, we cannot have a chain (pkt->next == NULL) ++ */ ++ brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n", ++ write ? "TX" : "RX", pkt->len); ++ mypkt = brcmu_pkt_buf_get_skb(pkt->len); ++ if (!mypkt) { ++ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", ++ pkt->len); ++ return -EIO; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) ++ memcpy(mypkt->data, pkt->data, pkt->len); ++ ++ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, ++ func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) ++ memcpy(pkt->data, mypkt->data, mypkt->len); ++ ++ brcmu_pkt_buf_free_skb(mypkt); ++ } else { /* case 3: We have a packet and ++ it is aligned. */ ++ brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n", ++ write ? "Tx" : "Rx"); ++ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, ++ func, addr, pkt); ++ } ++ ++ return Status; ++} ++ ++/* Read client card reg */ ++static int ++brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr, ++ int regsize, u32 *data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ u8 temp = 0; ++ ++ brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr, ++ &temp); ++ *data = temp; ++ *data &= 0xff; ++ brcmf_dbg(DATA, "byte read data=0x%02x\n", *data); ++ } else { ++ brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr, ++ data, regsize); ++ if (regsize == 2) ++ *data &= 0xffff; ++ ++ brcmf_dbg(DATA, "word read data=0x%08x\n", *data); ++ } ++ ++ return SUCCESS; ++} ++ ++static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr) ++{ ++ /* read 24 bits and return valid 17 bit addr */ ++ int i; ++ u32 scratch, regdata; ++ __le32 scratch_le; ++ u8 *ptr = (u8 *)&scratch_le; ++ ++ for (i = 0; i < 3; i++) { ++ if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1, ++ ®data)) != SUCCESS) ++ brcmf_dbg(ERROR, "Can't read!\n"); ++ ++ *ptr++ = (u8) regdata; ++ regaddr++; ++ } ++ ++ /* Only the lower 17-bits are valid */ ++ scratch = le32_to_cpu(scratch_le); ++ scratch &= 0x0001FFFF; ++ return scratch; ++} ++ ++static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) ++{ ++ int err_ret; ++ u32 fbraddr; ++ u8 func; ++ ++ brcmf_dbg(TRACE, "\n"); ++ ++ /* Get the Card's common CIS address */ ++ sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev, ++ SDIO_CCCR_CIS); ++ brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n", ++ sdiodev->func_cis_ptr[0]); ++ ++ /* Get the Card's function CIS (for each function) */ ++ for (fbraddr = SDIO_FBR_BASE(1), func = 1; ++ func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { ++ sdiodev->func_cis_ptr[func] = ++ brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr); ++ brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n", ++ func, sdiodev->func_cis_ptr[func]); ++ } ++ ++ /* Enable Function 1 */ ++ sdio_claim_host(sdiodev->func[1]); ++ err_ret = sdio_enable_func(sdiodev->func[1]); ++ sdio_release_host(sdiodev->func[1]); ++ if (err_ret) ++ brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret); ++ ++ return false; ++} ++ ++/* ++ * Public entry points & extern's ++ */ ++int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) ++{ ++ int err_ret = 0; ++ ++ brcmf_dbg(TRACE, "\n"); ++ ++ sdiodev->num_funcs = 2; ++ ++ sdio_claim_host(sdiodev->func[1]); ++ err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); ++ sdio_release_host(sdiodev->func[1]); ++ if (err_ret) { ++ brcmf_dbg(ERROR, "Failed to set F1 blocksize\n"); ++ goto out; ++ } ++ ++ sdio_claim_host(sdiodev->func[2]); ++ err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); ++ sdio_release_host(sdiodev->func[2]); ++ if (err_ret) { ++ brcmf_dbg(ERROR, "Failed to set F2 blocksize\n"); ++ goto out; ++ } ++ ++ brcmf_sdioh_enablefuncs(sdiodev); ++ ++out: ++ brcmf_dbg(TRACE, "Done\n"); ++ return err_ret; ++} ++ ++void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) ++{ ++ brcmf_dbg(TRACE, "\n"); ++ ++ /* Disable Function 2 */ ++ sdio_claim_host(sdiodev->func[2]); ++ sdio_disable_func(sdiodev->func[2]); ++ sdio_release_host(sdiodev->func[2]); ++ ++ /* Disable Function 1 */ ++ sdio_claim_host(sdiodev->func[1]); ++ sdio_disable_func(sdiodev->func[1]); ++ sdio_release_host(sdiodev->func[1]); ++ ++} ++ ++static int brcmf_ops_sdio_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int ret = 0; ++ struct brcmf_sdio_dev *sdiodev; ++ brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_dbg(TRACE, "func->class=%x\n", func->class); ++ brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); ++ brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device); ++ brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num); ++ ++ if (func->num == 1) { ++ if (dev_get_drvdata(&func->card->dev)) { ++ brcmf_dbg(ERROR, "card private drvdata occupied\n"); ++ return -ENXIO; ++ } ++ sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); ++ if (!sdiodev) ++ return -ENOMEM; ++ sdiodev->func[0] = func->card->sdio_func[0]; ++ sdiodev->func[1] = func; ++ dev_set_drvdata(&func->card->dev, sdiodev); ++ ++ atomic_set(&sdiodev->suspend, false); ++ init_waitqueue_head(&sdiodev->request_byte_wait); ++ init_waitqueue_head(&sdiodev->request_word_wait); ++ init_waitqueue_head(&sdiodev->request_packet_wait); ++ init_waitqueue_head(&sdiodev->request_buffer_wait); ++ } ++ ++ if (func->num == 2) { ++ sdiodev = dev_get_drvdata(&func->card->dev); ++ if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) ++ return -ENODEV; ++ sdiodev->func[2] = func; ++ ++ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); ++ ret = brcmf_sdio_probe(sdiodev); ++ } ++ ++ return ret; ++} ++ ++static void brcmf_ops_sdio_remove(struct sdio_func *func) ++{ ++ struct brcmf_sdio_dev *sdiodev; ++ brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_dbg(INFO, "func->class=%x\n", func->class); ++ brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor); ++ brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device); ++ brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); ++ ++ if (func->num == 2) { ++ sdiodev = dev_get_drvdata(&func->card->dev); ++ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); ++ brcmf_sdio_remove(sdiodev); ++ dev_set_drvdata(&func->card->dev, NULL); ++ kfree(sdiodev); ++ } ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int brcmf_sdio_suspend(struct device *dev) ++{ ++ mmc_pm_flag_t sdio_flags; ++ struct brcmf_sdio_dev *sdiodev; ++ struct sdio_func *func = dev_to_sdio_func(dev); ++ int ret = 0; ++ ++ brcmf_dbg(TRACE, "\n"); ++ ++ sdiodev = dev_get_drvdata(&func->card->dev); ++ ++ atomic_set(&sdiodev->suspend, true); ++ ++ sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ brcmf_dbg(ERROR, "Host can't keep power while suspended\n"); ++ return -EINVAL; ++ } ++ ++ ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); ++ if (ret) { ++ brcmf_dbg(ERROR, "Failed to set pm_flags\n"); ++ return ret; ++ } ++ ++ brcmf_sdio_wdtmr_enable(sdiodev, false); ++ ++ return ret; ++} ++ ++static int brcmf_sdio_resume(struct device *dev) ++{ ++ struct brcmf_sdio_dev *sdiodev; ++ struct sdio_func *func = dev_to_sdio_func(dev); ++ ++ sdiodev = dev_get_drvdata(&func->card->dev); ++ brcmf_sdio_wdtmr_enable(sdiodev, true); ++ atomic_set(&sdiodev->suspend, false); ++ return 0; ++} ++ ++static const struct dev_pm_ops brcmf_sdio_pm_ops = { ++ .suspend = brcmf_sdio_suspend, ++ .resume = brcmf_sdio_resume, ++}; ++#endif /* CONFIG_PM_SLEEP */ ++ ++static struct sdio_driver brcmf_sdmmc_driver = { ++ .probe = brcmf_ops_sdio_probe, ++ .remove = brcmf_ops_sdio_remove, ++ .name = "brcmfmac", ++ .id_table = brcmf_sdmmc_ids, ++#ifdef CONFIG_PM_SLEEP ++ .drv = { ++ .pm = &brcmf_sdio_pm_ops, ++ }, ++#endif /* CONFIG_PM_SLEEP */ ++}; ++ ++/* bus register interface */ ++int brcmf_bus_register(void) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ return sdio_register_driver(&brcmf_sdmmc_driver); ++} ++ ++void brcmf_bus_unregister(void) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ sdio_unregister_driver(&brcmf_sdmmc_driver); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h.orig 2011-11-09 13:46:58.229800834 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h 2011-11-09 13:47:16.980566416 -0500 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCMF_BUS_H_ ++#define _BRCMF_BUS_H_ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#define BRCMF_SDALIGN (1 << 6) ++ ++/* watchdog polling interval in ms */ ++#define BRCMF_WD_POLL_MS 10 ++ ++/* ++ * Exported from brcmf bus module (brcmf_usb, brcmf_sdio) ++ */ ++ ++/* Indicate (dis)interest in finding dongles. */ ++extern int brcmf_bus_register(void); ++extern void brcmf_bus_unregister(void); ++ ++/* obtain linux device object providing bus function */ ++extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus); ++ ++/* Stop bus module: clear pending frames, disable data flow */ ++extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus); ++ ++/* Initialize bus module: prepare for communication w/dongle */ ++extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr); ++ ++/* Send a data frame to the dongle. Callee disposes of txp. */ ++extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); ++ ++/* Send/receive a control message to/from the dongle. ++ * Expects caller to enforce a single outstanding transaction. ++ */ ++extern int ++brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); ++ ++extern int ++brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); ++ ++extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); ++ ++#endif /* _BRCMF_BUS_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c.orig 2011-11-09 13:46:58.230800821 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c 2011-11-09 13:47:16.981566403 -0500 +@@ -0,0 +1,498 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/******************************************************************************* ++ * Communicates with the dongle by using dcmd codes. ++ * For certain dcmd codes, the dongle interprets string data from the host. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "dhd.h" ++#include "dhd_proto.h" ++#include "dhd_bus.h" ++#include "dhd_dbg.h" ++ ++struct brcmf_proto_cdc_dcmd { ++ __le32 cmd; /* dongle command value */ ++ __le32 len; /* lower 16: output buflen; ++ * upper 16: input buflen (excludes header) */ ++ __le32 flags; /* flag defns given below */ ++ __le32 status; /* status code returned from the device */ ++}; ++ ++/* Max valid buffer size that can be sent to the dongle */ ++#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) ++ ++/* CDC flag definitions */ ++#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ ++#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ ++#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ ++#define CDC_DCMD_IF_SHIFT 12 ++#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ ++#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ ++#define CDC_DCMD_ID(flags) \ ++ (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) ++ ++/* ++ * BDC header - Broadcom specific extension of CDC. ++ * Used on data packets to convey priority across USB. ++ */ ++#define BDC_HEADER_LEN 4 ++#define BDC_PROTO_VER 1 /* Protocol version */ ++#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ ++#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ ++#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ ++#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ ++#define BDC_PRIORITY_MASK 0x7 ++#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ ++#define BDC_FLAG2_IF_SHIFT 0 ++ ++#define BDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) ++#define BDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ ++ ((idx) << BDC_FLAG2_IF_SHIFT))) ++ ++struct brcmf_proto_bdc_header { ++ u8 flags; ++ u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */ ++ u8 flags2; ++ u8 rssi; ++}; ++ ++ ++#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ ++#define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE ++ * (amount of header tha might be added) ++ * plus any space that might be needed ++ * for alignment padding. ++ */ ++#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for ++ * round off at the end of buffer ++ */ ++ ++struct brcmf_proto { ++ u16 reqid; ++ u8 pending; ++ u32 lastcmd; ++ u8 bus_header[BUS_HEADER_LEN]; ++ struct brcmf_proto_cdc_dcmd msg; ++ unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; ++}; ++ ++static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) ++{ ++ struct brcmf_proto *prot = drvr->prot; ++ int len = le32_to_cpu(prot->msg.len) + ++ sizeof(struct brcmf_proto_cdc_dcmd); ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* NOTE : cdc->msg.len holds the desired length of the buffer to be ++ * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area ++ * is actually sent to the dongle ++ */ ++ if (len > CDC_MAX_MSG_SIZE) ++ len = CDC_MAX_MSG_SIZE; ++ ++ /* Send request */ ++ return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, ++ len); ++} ++ ++static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) ++{ ++ int ret; ++ struct brcmf_proto *prot = drvr->prot; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ do { ++ ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, ++ (unsigned char *)&prot->msg, ++ len + sizeof(struct brcmf_proto_cdc_dcmd)); ++ if (ret < 0) ++ break; ++ } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); ++ ++ return ret; ++} ++ ++int ++brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, ++ void *buf, uint len) ++{ ++ struct brcmf_proto *prot = drvr->prot; ++ struct brcmf_proto_cdc_dcmd *msg = &prot->msg; ++ void *info; ++ int ret = 0, retries = 0; ++ u32 id, flags; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); ++ ++ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ ++ if (cmd == BRCMF_C_GET_VAR && buf) { ++ if (!strcmp((char *)buf, "bcmerrorstr")) { ++ strncpy((char *)buf, "bcm_error", ++ BCME_STRLEN); ++ goto done; ++ } else if (!strcmp((char *)buf, "bcmerror")) { ++ *(int *)buf = drvr->dongle_error; ++ goto done; ++ } ++ } ++ ++ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); ++ ++ msg->cmd = cpu_to_le32(cmd); ++ msg->len = cpu_to_le32(len); ++ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); ++ flags = (flags & ~CDC_DCMD_IF_MASK) | ++ (ifidx << CDC_DCMD_IF_SHIFT); ++ msg->flags = cpu_to_le32(flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ ret = brcmf_proto_cdc_msg(drvr); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "brcmf_proto_cdc_msg failed w/status %d\n", ++ ret); ++ goto done; ++ } ++ ++retry: ++ /* wait for interrupt and get first fragment */ ++ ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); ++ if (ret < 0) ++ goto done; ++ ++ flags = le32_to_cpu(msg->flags); ++ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; ++ ++ if ((id < prot->reqid) && (++retries < RETRIES)) ++ goto retry; ++ if (id != prot->reqid) { ++ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", ++ brcmf_ifname(drvr, ifidx), id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check info buffer */ ++ info = (void *)&msg[1]; ++ ++ /* Copy info buffer */ ++ if (buf) { ++ if (ret < (int)len) ++ len = ret; ++ memcpy(buf, info, len); ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDC_DCMD_ERROR) { ++ ret = le32_to_cpu(msg->status); ++ /* Cache error from dongle */ ++ drvr->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, ++ void *buf, uint len) ++{ ++ struct brcmf_proto *prot = drvr->prot; ++ struct brcmf_proto_cdc_dcmd *msg = &prot->msg; ++ int ret = 0; ++ u32 flags, id; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); ++ ++ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); ++ ++ msg->cmd = cpu_to_le32(cmd); ++ msg->len = cpu_to_le32(len); ++ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; ++ flags = (flags & ~CDC_DCMD_IF_MASK) | ++ (ifidx << CDC_DCMD_IF_SHIFT); ++ msg->flags = cpu_to_le32(flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ ret = brcmf_proto_cdc_msg(drvr); ++ if (ret < 0) ++ goto done; ++ ++ ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); ++ if (ret < 0) ++ goto done; ++ ++ flags = le32_to_cpu(msg->flags); ++ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; ++ ++ if (id != prot->reqid) { ++ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", ++ brcmf_ifname(drvr, ifidx), id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDC_DCMD_ERROR) { ++ ret = le32_to_cpu(msg->status); ++ /* Cache error from dongle */ ++ drvr->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++int ++brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, ++ int len) ++{ ++ struct brcmf_proto *prot = drvr->prot; ++ int ret = -1; ++ ++ if (drvr->busstate == BRCMF_BUS_DOWN) { ++ brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); ++ return ret; ++ } ++ brcmf_os_proto_block(drvr); ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (len > BRCMF_DCMD_MAXLEN) ++ goto done; ++ ++ if (prot->pending == true) { ++ brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", ++ dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd, ++ (unsigned long)prot->lastcmd); ++ if (dcmd->cmd == BRCMF_C_SET_VAR || ++ dcmd->cmd == BRCMF_C_GET_VAR) ++ brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf); ++ ++ goto done; ++ } ++ ++ prot->pending = true; ++ prot->lastcmd = dcmd->cmd; ++ if (dcmd->set) ++ ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd, ++ dcmd->buf, len); ++ else { ++ ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd, ++ dcmd->buf, len); ++ if (ret > 0) ++ dcmd->used = ret - ++ sizeof(struct brcmf_proto_cdc_dcmd); ++ } ++ ++ if (ret >= 0) ++ ret = 0; ++ else { ++ struct brcmf_proto_cdc_dcmd *msg = &prot->msg; ++ /* len == needed when set/query fails from dongle */ ++ dcmd->needed = le32_to_cpu(msg->len); ++ } ++ ++ /* Intercept the wme_dp dongle cmd here */ ++ if (!ret && dcmd->cmd == BRCMF_C_SET_VAR && ++ !strcmp(dcmd->buf, "wme_dp")) { ++ int slen; ++ __le32 val = 0; ++ ++ slen = strlen("wme_dp") + 1; ++ if (len >= (int)(slen + sizeof(int))) ++ memcpy(&val, (char *)dcmd->buf + slen, sizeof(int)); ++ drvr->wme_dp = (u8) le32_to_cpu(val); ++ } ++ ++ prot->pending = false; ++ ++done: ++ brcmf_os_proto_unblock(drvr); ++ ++ return ret; ++} ++ ++static bool pkt_sum_needed(struct sk_buff *skb) ++{ ++ return skb->ip_summed == CHECKSUM_PARTIAL; ++} ++ ++static void pkt_set_sum_good(struct sk_buff *skb, bool x) ++{ ++ skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); ++} ++ ++void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, ++ struct sk_buff *pktbuf) ++{ ++ struct brcmf_proto_bdc_header *h; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Push BDC header used to convey priority for buses that don't */ ++ ++ skb_push(pktbuf, BDC_HEADER_LEN); ++ ++ h = (struct brcmf_proto_bdc_header *)(pktbuf->data); ++ ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (pkt_sum_needed(pktbuf)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->rssi = 0; ++ BDC_SET_IF_IDX(h, ifidx); ++} ++ ++int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx, ++ struct sk_buff *pktbuf) ++{ ++ struct brcmf_proto_bdc_header *h; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Pop BDC header used to convey priority for buses that don't */ ++ ++ if (pktbuf->len < BDC_HEADER_LEN) { ++ brcmf_dbg(ERROR, "rx data too short (%d < %d)\n", ++ pktbuf->len, BDC_HEADER_LEN); ++ return -EBADE; ++ } ++ ++ h = (struct brcmf_proto_bdc_header *)(pktbuf->data); ++ ++ *ifidx = BDC_GET_IF_IDX(h); ++ if (*ifidx >= BRCMF_MAX_IFS) { ++ brcmf_dbg(ERROR, "rx data ifnum out of range (%d)\n", *ifidx); ++ return -EBADE; ++ } ++ ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != ++ BDC_PROTO_VER) { ++ brcmf_dbg(ERROR, "%s: non-BDC packet received, flags 0x%x\n", ++ brcmf_ifname(drvr, *ifidx), h->flags); ++ return -EBADE; ++ } ++ ++ if (h->flags & BDC_FLAG_SUM_GOOD) { ++ brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n", ++ brcmf_ifname(drvr, *ifidx), h->flags); ++ pkt_set_sum_good(pktbuf, true); ++ } ++ ++ pktbuf->priority = h->priority & BDC_PRIORITY_MASK; ++ ++ skb_pull(pktbuf, BDC_HEADER_LEN); ++ ++ return 0; ++} ++ ++int brcmf_proto_attach(struct brcmf_pub *drvr) ++{ ++ struct brcmf_proto *cdc; ++ ++ cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); ++ if (!cdc) ++ goto fail; ++ ++ /* ensure that the msg buf directly follows the cdc msg struct */ ++ if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { ++ brcmf_dbg(ERROR, "struct brcmf_proto is not correctly defined\n"); ++ goto fail; ++ } ++ ++ drvr->prot = cdc; ++ drvr->hdrlen += BDC_HEADER_LEN; ++ drvr->maxctl = BRCMF_DCMD_MAXLEN + ++ sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; ++ return 0; ++ ++fail: ++ kfree(cdc); ++ return -ENOMEM; ++} ++ ++/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ ++void brcmf_proto_detach(struct brcmf_pub *drvr) ++{ ++ kfree(drvr->prot); ++ drvr->prot = NULL; ++} ++ ++void brcmf_proto_dstats(struct brcmf_pub *drvr) ++{ ++ /* No stats from dongle added yet, copy bus stats */ ++ drvr->dstats.tx_packets = drvr->tx_packets; ++ drvr->dstats.tx_errors = drvr->tx_errors; ++ drvr->dstats.rx_packets = drvr->rx_packets; ++ drvr->dstats.rx_errors = drvr->rx_errors; ++ drvr->dstats.rx_dropped = drvr->rx_dropped; ++ drvr->dstats.multicast = drvr->rx_multicast; ++ return; ++} ++ ++int brcmf_proto_init(struct brcmf_pub *drvr) ++{ ++ int ret = 0; ++ char buf[128]; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ brcmf_os_proto_block(drvr); ++ ++ /* Get the device MAC address */ ++ strcpy(buf, "cur_etheraddr"); ++ ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, ++ buf, sizeof(buf)); ++ if (ret < 0) { ++ brcmf_os_proto_unblock(drvr); ++ return ret; ++ } ++ memcpy(drvr->mac, buf, ETH_ALEN); ++ ++ brcmf_os_proto_unblock(drvr); ++ ++ ret = brcmf_c_preinit_dcmds(drvr); ++ ++ /* Always assumes wl for now */ ++ drvr->iswl = true; ++ ++ return ret; ++} ++ ++void brcmf_proto_stop(struct brcmf_pub *drvr) ++{ ++ /* Nothing to do for CDC */ ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c.orig 2011-11-09 13:46:58.230800821 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c 2011-11-09 13:47:16.981566403 -0500 +@@ -0,0 +1,895 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dhd.h" ++#include "dhd_bus.h" ++#include "dhd_proto.h" ++#include "dhd_dbg.h" ++ ++#define BRCM_OUI "\x00\x10\x18" ++#define DOT11_OUI_LEN 3 ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define PKTFILTER_BUF_SIZE 2048 ++#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ ++ ++int brcmf_msg_level; ++ ++#define MSGTRACE_VERSION 1 ++ ++#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u) ++#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ ++ offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern) ++ ++#ifdef BCMDBG ++static const char brcmf_version[] = ++ "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " ++ __DATE__ " at " __TIME__; ++#else ++static const char brcmf_version[] = ++ "Dongle Host Driver, version " BRCMF_VERSION_STR; ++#endif ++ ++/* Message trace header */ ++struct msgtrace_hdr { ++ u8 version; ++ u8 spare; ++ __be16 len; /* Len of the trace */ ++ __be32 seqnum; /* Sequence number of message. Useful ++ * if the messsage has been lost ++ * because of DMA error or a bus reset ++ * (ex: SDIO Func2) ++ */ ++ __be32 discarded_bytes; /* Number of discarded bytes because of ++ trace overflow */ ++ __be32 discarded_printf; /* Number of discarded printf ++ because of trace overflow */ ++} __packed; ++ ++ ++uint ++brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) ++{ ++ uint len; ++ ++ len = strlen(name) + 1; ++ ++ if ((len + datalen) > buflen) ++ return 0; ++ ++ strncpy(buf, name, buflen); ++ ++ /* append data onto the end of the name string */ ++ memcpy(&buf[len], data, datalen); ++ len += datalen; ++ ++ return len; ++} ++ ++void brcmf_c_init(void) ++{ ++ /* Init global variables at run-time, not as part of the declaration. ++ * This is required to support init/de-init of the driver. ++ * Initialization ++ * of globals as part of the declaration results in non-deterministic ++ * behaviour since the value of the globals may be different on the ++ * first time that the driver is initialized vs subsequent ++ * initializations. ++ */ ++ brcmf_msg_level = BRCMF_ERROR_VAL; ++} ++ ++bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, ++ struct sk_buff *pkt, int prec) ++{ ++ struct sk_buff *p; ++ int eprec = -1; /* precedence to evict from */ ++ bool discard_oldest; ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(q, prec) && !pktq_full(q)) { ++ brcmu_pktq_penq(q, prec, pkt); ++ return true; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(q, prec)) ++ eprec = prec; ++ else if (pktq_full(q)) { ++ p = brcmu_pktq_peek_tail(q, &eprec); ++ if (eprec > prec) ++ return false; ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); ++ if (eprec == prec && !discard_oldest) ++ return false; /* refuse newer (incoming) packet */ ++ /* Evict packet according to discard policy */ ++ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : ++ brcmu_pktq_pdeq_tail(q, eprec); ++ if (p == NULL) ++ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n", ++ discard_oldest); ++ ++ brcmu_pkt_buf_free_skb(p); ++ } ++ ++ /* Enqueue */ ++ p = brcmu_pktq_penq(q, prec, pkt); ++ if (p == NULL) ++ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n"); ++ ++ return p != NULL; ++} ++ ++#ifdef BCMDBG ++static void ++brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) ++{ ++ uint i, status, reason; ++ bool group = false, flush_txq = false, link = false; ++ char *auth_str, *event_name; ++ unsigned char *buf; ++ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; ++ static struct { ++ uint event; ++ char *event_name; ++ } event_names[] = { ++ { ++ BRCMF_E_SET_SSID, "SET_SSID"}, { ++ BRCMF_E_JOIN, "JOIN"}, { ++ BRCMF_E_START, "START"}, { ++ BRCMF_E_AUTH, "AUTH"}, { ++ BRCMF_E_AUTH_IND, "AUTH_IND"}, { ++ BRCMF_E_DEAUTH, "DEAUTH"}, { ++ BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, { ++ BRCMF_E_ASSOC, "ASSOC"}, { ++ BRCMF_E_ASSOC_IND, "ASSOC_IND"}, { ++ BRCMF_E_REASSOC, "REASSOC"}, { ++ BRCMF_E_REASSOC_IND, "REASSOC_IND"}, { ++ BRCMF_E_DISASSOC, "DISASSOC"}, { ++ BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, { ++ BRCMF_E_QUIET_START, "START_QUIET"}, { ++ BRCMF_E_QUIET_END, "END_QUIET"}, { ++ BRCMF_E_BEACON_RX, "BEACON_RX"}, { ++ BRCMF_E_LINK, "LINK"}, { ++ BRCMF_E_MIC_ERROR, "MIC_ERROR"}, { ++ BRCMF_E_NDIS_LINK, "NDIS_LINK"}, { ++ BRCMF_E_ROAM, "ROAM"}, { ++ BRCMF_E_TXFAIL, "TXFAIL"}, { ++ BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, { ++ BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, { ++ BRCMF_E_PRUNE, "PRUNE"}, { ++ BRCMF_E_AUTOAUTH, "AUTOAUTH"}, { ++ BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, { ++ BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, { ++ BRCMF_E_ADDTS_IND, "ADDTS_IND"}, { ++ BRCMF_E_DELTS_IND, "DELTS_IND"}, { ++ BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, { ++ BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, { ++ BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, { ++ BRCMF_E_ROAM_PREP, "ROAM_PREP"}, { ++ BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, { ++ BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, { ++ BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, { ++ BRCMF_E_JOIN_START, "JOIN_START"}, { ++ BRCMF_E_ROAM_START, "ROAM_START"}, { ++ BRCMF_E_ASSOC_START, "ASSOC_START"}, { ++ BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, { ++ BRCMF_E_RADIO, "RADIO"}, { ++ BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, { ++ BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, { ++ BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, { ++ BRCMF_E_PSK_SUP, "PSK_SUP"}, { ++ BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, { ++ BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, { ++ BRCMF_E_ICV_ERROR, "ICV_ERROR"}, { ++ BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, { ++ BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, { ++ BRCMF_E_TRACE, "TRACE"}, { ++ BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, { ++ BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { ++ BRCMF_E_IF, "IF"}, { ++ BRCMF_E_RSSI, "RSSI"}, { ++ BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} ++ }; ++ uint event_type, flags, auth_type, datalen; ++ static u32 seqnum_prev; ++ struct msgtrace_hdr hdr; ++ u32 nblost; ++ char *s, *p; ++ ++ event_type = be32_to_cpu(event->event_type); ++ flags = be16_to_cpu(event->flags); ++ status = be32_to_cpu(event->status); ++ reason = be32_to_cpu(event->reason); ++ auth_type = be32_to_cpu(event->auth_type); ++ datalen = be32_to_cpu(event->datalen); ++ /* debug dump of event messages */ ++ sprintf(eabuf, "%pM", event->addr); ++ ++ event_name = "UNKNOWN"; ++ for (i = 0; i < ARRAY_SIZE(event_names); i++) { ++ if (event_names[i].event == event_type) ++ event_name = event_names[i].event_name; ++ } ++ ++ brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type); ++ brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n", ++ flags, status, reason, auth_type, eabuf); ++ ++ if (flags & BRCMF_EVENT_MSG_LINK) ++ link = true; ++ if (flags & BRCMF_EVENT_MSG_GROUP) ++ group = true; ++ if (flags & BRCMF_EVENT_MSG_FLUSHTXQ) ++ flush_txq = true; ++ ++ switch (event_type) { ++ case BRCMF_E_START: ++ case BRCMF_E_DEAUTH: ++ case BRCMF_E_DISASSOC: ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case BRCMF_E_ASSOC_IND: ++ case BRCMF_E_REASSOC_IND: ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case BRCMF_E_ASSOC: ++ case BRCMF_E_REASSOC: ++ if (status == BRCMF_E_STATUS_SUCCESS) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n", ++ event_name, eabuf); ++ else if (status == BRCMF_E_STATUS_TIMEOUT) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n", ++ event_name, eabuf); ++ else if (status == BRCMF_E_STATUS_FAIL) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n", ++ event_name, eabuf, (int)reason); ++ else ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n", ++ event_name, eabuf, (int)status); ++ break; ++ ++ case BRCMF_E_DEAUTH_IND: ++ case BRCMF_E_DISASSOC_IND: ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n", ++ event_name, eabuf, (int)reason); ++ break; ++ ++ case BRCMF_E_AUTH: ++ case BRCMF_E_AUTH_IND: ++ if (auth_type == WLAN_AUTH_OPEN) ++ auth_str = "Open System"; ++ else if (auth_type == WLAN_AUTH_SHARED_KEY) ++ auth_str = "Shared Key"; ++ else { ++ sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); ++ auth_str = err_msg; ++ } ++ if (event_type == BRCMF_E_AUTH_IND) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n", ++ event_name, eabuf, auth_str); ++ else if (status == BRCMF_E_STATUS_SUCCESS) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n", ++ event_name, eabuf, auth_str); ++ else if (status == BRCMF_E_STATUS_TIMEOUT) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n", ++ event_name, eabuf, auth_str); ++ else if (status == BRCMF_E_STATUS_FAIL) { ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", ++ event_name, eabuf, auth_str, (int)reason); ++ } ++ ++ break; ++ ++ case BRCMF_E_JOIN: ++ case BRCMF_E_ROAM: ++ case BRCMF_E_SET_SSID: ++ if (status == BRCMF_E_STATUS_SUCCESS) ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", ++ event_name, eabuf); ++ else if (status == BRCMF_E_STATUS_FAIL) ++ brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name); ++ else if (status == BRCMF_E_STATUS_NO_NETWORKS) ++ brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n", ++ event_name); ++ else ++ brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n", ++ event_name, (int)status); ++ break; ++ ++ case BRCMF_E_BEACON_RX: ++ if (status == BRCMF_E_STATUS_SUCCESS) ++ brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name); ++ else if (status == BRCMF_E_STATUS_FAIL) ++ brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name); ++ else ++ brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n", ++ event_name, status); ++ break; ++ ++ case BRCMF_E_LINK: ++ brcmf_dbg(EVENT, "MACEVENT: %s %s\n", ++ event_name, link ? "UP" : "DOWN"); ++ break; ++ ++ case BRCMF_E_MIC_ERROR: ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n", ++ event_name, eabuf, group, flush_txq); ++ break; ++ ++ case BRCMF_E_ICV_ERROR: ++ case BRCMF_E_UNICAST_DECODE_ERROR: ++ case BRCMF_E_MULTICAST_DECODE_ERROR: ++ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case BRCMF_E_TXFAIL: ++ brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf); ++ break; ++ ++ case BRCMF_E_SCAN_COMPLETE: ++ case BRCMF_E_PMKID_CACHE: ++ brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); ++ break; ++ ++ case BRCMF_E_PFN_NET_FOUND: ++ case BRCMF_E_PFN_NET_LOST: ++ case BRCMF_E_PFN_SCAN_COMPLETE: ++ brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name); ++ break; ++ ++ case BRCMF_E_PSK_SUP: ++ case BRCMF_E_PRUNE: ++ brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n", ++ event_name, (int)status, (int)reason); ++ break; ++ ++ case BRCMF_E_TRACE: ++ buf = (unsigned char *) event_data; ++ memcpy(&hdr, buf, sizeof(struct msgtrace_hdr)); ++ ++ if (hdr.version != MSGTRACE_VERSION) { ++ brcmf_dbg(ERROR, ++ "MACEVENT: %s [unsupported version --> brcmf" ++ " version:%d dongle version:%d]\n", ++ event_name, MSGTRACE_VERSION, hdr.version); ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ } ++ ++ /* There are 2 bytes available at the end of data */ ++ *(buf + sizeof(struct msgtrace_hdr) ++ + be16_to_cpu(hdr.len)) = '\0'; ++ ++ if (be32_to_cpu(hdr.discarded_bytes) ++ || be32_to_cpu(hdr.discarded_printf)) ++ brcmf_dbg(ERROR, ++ "WLC_E_TRACE: [Discarded traces in dongle -->" ++ " discarded_bytes %d discarded_printf %d]\n", ++ be32_to_cpu(hdr.discarded_bytes), ++ be32_to_cpu(hdr.discarded_printf)); ++ ++ nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1; ++ if (nblost > 0) ++ brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum " ++ " %d nblost %d\n", be32_to_cpu(hdr.seqnum), ++ nblost); ++ seqnum_prev = be32_to_cpu(hdr.seqnum); ++ ++ /* Display the trace buffer. Advance from \n to \n to ++ * avoid display big ++ * printf (issue with Linux printk ) ++ */ ++ p = (char *)&buf[sizeof(struct msgtrace_hdr)]; ++ while ((s = strstr(p, "\n")) != NULL) { ++ *s = '\0'; ++ printk(KERN_DEBUG"%s\n", p); ++ p = s + 1; ++ } ++ printk(KERN_DEBUG "%s\n", p); ++ ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ ++ case BRCMF_E_RSSI: ++ brcmf_dbg(EVENT, "MACEVENT: %s %d\n", ++ event_name, be32_to_cpu(*((__be32 *)event_data))); ++ break; ++ ++ default: ++ brcmf_dbg(EVENT, ++ "MACEVENT: %s %d, MAC %s, status %d, reason %d, " ++ "auth %d\n", event_name, event_type, eabuf, ++ (int)status, (int)reason, (int)auth_type); ++ break; ++ } ++ ++ /* show any appended data */ ++ if (datalen) { ++ buf = (unsigned char *) event_data; ++ brcmf_dbg(EVENT, " data (%d) : ", datalen); ++ for (i = 0; i < datalen; i++) ++ brcmf_dbg(EVENT, " 0x%02x ", *buf++); ++ brcmf_dbg(EVENT, "\n"); ++ } ++} ++#endif /* BCMDBG */ ++ ++int ++brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, ++ struct brcmf_event_msg *event, void **data_ptr) ++{ ++ /* check whether packet is a BRCM event pkt */ ++ struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; ++ struct brcmf_if_event *ifevent; ++ char *event_data; ++ u32 type, status; ++ u16 flags; ++ int evlen; ++ ++ if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { ++ brcmf_dbg(ERROR, "mismatched OUI, bailing\n"); ++ return -EBADE; ++ } ++ ++ /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ ++ if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != ++ BCMILCP_BCM_SUBTYPE_EVENT) { ++ brcmf_dbg(ERROR, "mismatched subtype, bailing\n"); ++ return -EBADE; ++ } ++ ++ *data_ptr = &pvt_data[1]; ++ event_data = *data_ptr; ++ ++ /* memcpy since BRCM event pkt may be unaligned. */ ++ memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); ++ ++ type = get_unaligned_be32(&event->event_type); ++ flags = get_unaligned_be16(&event->flags); ++ status = get_unaligned_be32(&event->status); ++ evlen = get_unaligned_be32(&event->datalen) + ++ sizeof(struct brcmf_event); ++ ++ switch (type) { ++ case BRCMF_E_IF: ++ ifevent = (struct brcmf_if_event *) event_data; ++ brcmf_dbg(TRACE, "if event\n"); ++ ++ if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { ++ if (ifevent->action == BRCMF_E_IF_ADD) ++ brcmf_add_if(drvr_priv, ifevent->ifidx, NULL, ++ event->ifname, ++ pvt_data->eth.h_dest, ++ ifevent->flags, ifevent->bssidx); ++ else ++ brcmf_del_if(drvr_priv, ifevent->ifidx); ++ } else { ++ brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n", ++ ifevent->ifidx, event->ifname); ++ } ++ ++ /* send up the if event: btamp user needs it */ ++ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); ++ break; ++ ++ /* These are what external supplicant/authenticator wants */ ++ case BRCMF_E_LINK: ++ case BRCMF_E_ASSOC_IND: ++ case BRCMF_E_REASSOC_IND: ++ case BRCMF_E_DISASSOC_IND: ++ case BRCMF_E_MIC_ERROR: ++ default: ++ /* Fall through: this should get _everything_ */ ++ ++ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); ++ brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n", ++ type, flags, status); ++ ++ /* put it back to BRCMF_E_NDIS_LINK */ ++ if (type == BRCMF_E_NDIS_LINK) { ++ u32 temp1; ++ __be32 temp2; ++ ++ temp1 = get_unaligned_be32(&event->event_type); ++ brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n", ++ temp1); ++ ++ temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK); ++ memcpy((void *)(&pvt_data->msg.event_type), &temp2, ++ sizeof(pvt_data->msg.event_type)); ++ } ++ break; ++ } ++ ++#ifdef BCMDBG ++ brcmf_c_show_host_event(event, event_data); ++#endif /* BCMDBG */ ++ ++ return 0; ++} ++ ++/* Convert user's input in hex pattern to byte-size mask */ ++static int brcmf_c_pattern_atoh(char *src, char *dst) ++{ ++ int i; ++ if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { ++ brcmf_dbg(ERROR, "Mask invalid format. Needs to start with 0x\n"); ++ return -EINVAL; ++ } ++ src = src + 2; /* Skip past 0x */ ++ if (strlen(src) % 2 != 0) { ++ brcmf_dbg(ERROR, "Mask invalid format. Length must be even.\n"); ++ return -EINVAL; ++ } ++ for (i = 0; *src != '\0'; i++) { ++ unsigned long res; ++ char num[3]; ++ strncpy(num, src, 2); ++ num[2] = '\0'; ++ if (kstrtoul(num, 16, &res)) ++ return -EINVAL; ++ dst[i] = (u8)res; ++ src += 2; ++ } ++ return i; ++} ++ ++void ++brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, ++ int master_mode) ++{ ++ unsigned long res; ++ char *argv[8]; ++ int i = 0; ++ const char *str; ++ int buf_len; ++ int str_len; ++ char *arg_save = NULL, *arg_org = NULL; ++ int rc; ++ char buf[128]; ++ struct brcmf_pkt_filter_enable_le enable_parm; ++ struct brcmf_pkt_filter_enable_le *pkt_filterp; ++ __le32 mmode_le; ++ ++ arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); ++ if (!arg_save) ++ goto fail; ++ ++ arg_org = arg_save; ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ argv[i] = strsep(&arg_save, " "); ++ ++ i = 0; ++ if (NULL == argv[i]) { ++ brcmf_dbg(ERROR, "No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_enable"; ++ str_len = strlen(str); ++ strncpy(buf, str, str_len); ++ buf[str_len] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ enable_parm.id = 0; ++ if (!kstrtoul(argv[i], 0, &res)) ++ enable_parm.id = cpu_to_le32((u32)res); ++ ++ /* Parse enable/disable value. */ ++ enable_parm.enable = cpu_to_le32(enable); ++ ++ buf_len += sizeof(enable_parm); ++ memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm)); ++ ++ /* Enable/disable the specified filter. */ ++ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", ++ arg, rc); ++ else ++ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); ++ ++ /* Contorl the master mode */ ++ mmode_le = cpu_to_le32(master_mode); ++ brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf, ++ sizeof(buf)); ++ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, ++ sizeof(buf)); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", ++ arg, rc); ++ ++fail: ++ kfree(arg_org); ++} ++ ++void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg) ++{ ++ const char *str; ++ struct brcmf_pkt_filter_le pkt_filter; ++ struct brcmf_pkt_filter_le *pkt_filterp; ++ unsigned long res; ++ int buf_len; ++ int str_len; ++ int rc; ++ u32 mask_size; ++ u32 pattern_size; ++ char *argv[8], *buf = NULL; ++ int i = 0; ++ char *arg_save = NULL, *arg_org = NULL; ++ ++ arg_save = kstrdup(arg, GFP_ATOMIC); ++ if (!arg_save) ++ goto fail; ++ ++ arg_org = arg_save; ++ ++ buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC); ++ if (!buf) ++ goto fail; ++ ++ argv[i] = strsep(&arg_save, " "); ++ while (argv[i++]) ++ argv[i] = strsep(&arg_save, " "); ++ ++ i = 0; ++ if (NULL == argv[i]) { ++ brcmf_dbg(ERROR, "No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_add"; ++ strcpy(buf, str); ++ str_len = strlen(str); ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ pkt_filter.id = 0; ++ if (!kstrtoul(argv[i], 0, &res)) ++ pkt_filter.id = cpu_to_le32((u32)res); ++ ++ if (NULL == argv[++i]) { ++ brcmf_dbg(ERROR, "Polarity not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter polarity. */ ++ pkt_filter.negate_match = 0; ++ if (!kstrtoul(argv[i], 0, &res)) ++ pkt_filter.negate_match = cpu_to_le32((u32)res); ++ ++ if (NULL == argv[++i]) { ++ brcmf_dbg(ERROR, "Filter type not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter type. */ ++ pkt_filter.type = 0; ++ if (!kstrtoul(argv[i], 0, &res)) ++ pkt_filter.type = cpu_to_le32((u32)res); ++ ++ if (NULL == argv[++i]) { ++ brcmf_dbg(ERROR, "Offset not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter offset. */ ++ pkt_filter.u.pattern.offset = 0; ++ if (!kstrtoul(argv[i], 0, &res)) ++ pkt_filter.u.pattern.offset = cpu_to_le32((u32)res); ++ ++ if (NULL == argv[++i]) { ++ brcmf_dbg(ERROR, "Bitmask not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter mask. */ ++ mask_size = ++ brcmf_c_pattern_atoh ++ (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern); ++ ++ if (NULL == argv[++i]) { ++ brcmf_dbg(ERROR, "Pattern not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter pattern. */ ++ pattern_size = ++ brcmf_c_pattern_atoh(argv[i], ++ (char *)&pkt_filterp->u.pattern. ++ mask_and_pattern[mask_size]); ++ ++ if (mask_size != pattern_size) { ++ brcmf_dbg(ERROR, "Mask and pattern not the same size\n"); ++ goto fail; ++ } ++ ++ pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size); ++ buf_len += BRCMF_PKT_FILTER_FIXED_LEN; ++ buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); ++ ++ /* Keep-alive attributes are set in local ++ * variable (keep_alive_pkt), and ++ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no ++ ** guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)pkt_filterp, ++ &pkt_filter, ++ BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN); ++ ++ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); ++ rc = rc >= 0 ? 0 : rc; ++ ++ if (rc) ++ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", ++ arg, rc); ++ else ++ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); ++ ++fail: ++ kfree(arg_org); ++ ++ kfree(buf); ++} ++ ++static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); ++ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, ++ iovbuf, sizeof(iovbuf)); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n", ++ arp_mode, retcode); ++ else ++ brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n", ++ arp_mode); ++} ++ ++static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4, ++ iovbuf, sizeof(iovbuf)); ++ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, ++ iovbuf, sizeof(iovbuf)); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n", ++ arp_enable, retcode); ++ else ++ brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n", ++ arp_enable); ++} ++ ++int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) ++{ ++ char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for ++ "event_msgs" + '\0' + bitvec */ ++ uint up = 0; ++ char buf[128], *ptr; ++ u32 dongle_align = BRCMF_SDALIGN; ++ u32 glom = 0; ++ u32 roaming = 1; ++ uint bcn_timeout = 3; ++ int scan_assoc_time = 40; ++ int scan_unassoc_time = 40; ++ int i; ++ ++ brcmf_os_proto_block(drvr); ++ ++ /* Set Country code */ ++ if (drvr->country_code[0] != 0) { ++ if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY, ++ drvr->country_code, ++ sizeof(drvr->country_code)) < 0) ++ brcmf_dbg(ERROR, "country code setting failed\n"); ++ } ++ ++ /* query for 'ver' to get version info from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ ptr = buf; ++ brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf)); ++ brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf)); ++ strsep(&ptr, "\n"); ++ /* Print fw version info */ ++ brcmf_dbg(ERROR, "Firmware version = %s\n", buf); ++ ++ /* Match Host and Dongle rx alignment */ ++ brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, ++ sizeof(iovbuf)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ ++ /* disable glom option per default */ ++ brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ ++ /* Setup timeout if Beacons are lost and roam is off to report ++ link down */ ++ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, ++ sizeof(iovbuf)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ ++ /* Enable/Disable build-in roaming to allowed ext supplicant to take ++ of romaing */ ++ brcmf_c_mkiovar("roam_off", (char *)&roaming, 4, ++ iovbuf, sizeof(iovbuf)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ ++ /* Force STA UP */ ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); ++ ++ /* Setup event_msgs */ ++ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, ++ (char *)&scan_assoc_time, sizeof(scan_assoc_time)); ++ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, ++ (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); ++ ++ /* Set and enable ARP offload feature */ ++ brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); ++ brcmf_c_arp_offload_enable(drvr, true); ++ ++ /* Set up pkt filter */ ++ for (i = 0; i < drvr->pktfilter_count; i++) { ++ brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]); ++ brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i], ++ 0, true); ++ } ++ ++ brcmf_os_proto_unblock(drvr); ++ ++ return 0; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h.orig 2011-11-09 13:46:58.231800808 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h 2011-11-09 13:47:16.981566403 -0500 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCMF_DBG_H_ ++#define _BRCMF_DBG_H_ ++ ++#if defined(BCMDBG) ++ ++#define brcmf_dbg(level, fmt, ...) \ ++do { \ ++ if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \ ++ if (brcmf_msg_level & BRCMF_##level##_VAL) { \ ++ if (net_ratelimit()) \ ++ printk(KERN_DEBUG "%s: " fmt, \ ++ __func__, ##__VA_ARGS__); \ ++ } \ ++ } else { \ ++ if (brcmf_msg_level & BRCMF_##level##_VAL) { \ ++ printk(KERN_DEBUG "%s: " fmt, \ ++ __func__, ##__VA_ARGS__); \ ++ } \ ++ } \ ++} while (0) ++ ++#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL) ++#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL) ++#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) ++#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) ++#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) ++ ++#else /* (defined BCMDBG) || (defined BCMDBG) */ ++ ++#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__) ++ ++#define BRCMF_DATA_ON() 0 ++#define BRCMF_CTL_ON() 0 ++#define BRCMF_HDRS_ON() 0 ++#define BRCMF_BYTES_ON() 0 ++#define BRCMF_GLOM_ON() 0 ++ ++#endif /* defined(BCMDBG) */ ++ ++extern int brcmf_msg_level; ++ ++#endif /* _BRCMF_DBG_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd.h.orig 2011-11-09 13:46:58.231800808 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd.h 2011-11-09 13:47:16.982566390 -0500 +@@ -0,0 +1,776 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/**************** ++ * Common types * ++ */ ++ ++#ifndef _BRCMF_H_ ++#define _BRCMF_H_ ++ ++#define BRCMF_VERSION_STR "4.218.248.5" ++ ++/******************************************************************************* ++ * IO codes that are interpreted by dongle firmware ++ ******************************************************************************/ ++#define BRCMF_C_UP 2 ++#define BRCMF_C_SET_PROMISC 10 ++#define BRCMF_C_GET_RATE 12 ++#define BRCMF_C_GET_INFRA 19 ++#define BRCMF_C_SET_INFRA 20 ++#define BRCMF_C_GET_AUTH 21 ++#define BRCMF_C_SET_AUTH 22 ++#define BRCMF_C_GET_BSSID 23 ++#define BRCMF_C_GET_SSID 25 ++#define BRCMF_C_SET_SSID 26 ++#define BRCMF_C_GET_CHANNEL 29 ++#define BRCMF_C_GET_SRL 31 ++#define BRCMF_C_GET_LRL 33 ++#define BRCMF_C_GET_RADIO 37 ++#define BRCMF_C_SET_RADIO 38 ++#define BRCMF_C_GET_PHYTYPE 39 ++#define BRCMF_C_SET_KEY 45 ++#define BRCMF_C_SET_PASSIVE_SCAN 49 ++#define BRCMF_C_SCAN 50 ++#define BRCMF_C_SCAN_RESULTS 51 ++#define BRCMF_C_DISASSOC 52 ++#define BRCMF_C_REASSOC 53 ++#define BRCMF_C_SET_ROAM_TRIGGER 55 ++#define BRCMF_C_SET_ROAM_DELTA 57 ++#define BRCMF_C_GET_DTIMPRD 77 ++#define BRCMF_C_SET_COUNTRY 84 ++#define BRCMF_C_GET_PM 85 ++#define BRCMF_C_SET_PM 86 ++#define BRCMF_C_GET_AP 117 ++#define BRCMF_C_SET_AP 118 ++#define BRCMF_C_GET_RSSI 127 ++#define BRCMF_C_GET_WSEC 133 ++#define BRCMF_C_SET_WSEC 134 ++#define BRCMF_C_GET_PHY_NOISE 135 ++#define BRCMF_C_GET_BSS_INFO 136 ++#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 ++#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 ++#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 ++#define BRCMF_C_GET_VALID_CHANNELS 217 ++#define BRCMF_C_GET_KEY_PRIMARY 235 ++#define BRCMF_C_SET_KEY_PRIMARY 236 ++#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 ++#define BRCMF_C_GET_VAR 262 ++#define BRCMF_C_SET_VAR 263 ++ ++/* phy types (returned by WLC_GET_PHYTPE) */ ++#define WLC_PHY_TYPE_A 0 ++#define WLC_PHY_TYPE_B 1 ++#define WLC_PHY_TYPE_G 2 ++#define WLC_PHY_TYPE_N 4 ++#define WLC_PHY_TYPE_LP 5 ++#define WLC_PHY_TYPE_SSN 6 ++#define WLC_PHY_TYPE_HT 7 ++#define WLC_PHY_TYPE_LCN 8 ++#define WLC_PHY_TYPE_NULL 0xf ++ ++#define BRCMF_EVENTING_MASK_LEN 16 ++ ++#define TOE_TX_CSUM_OL 0x00000001 ++#define TOE_RX_CSUM_OL 0x00000002 ++ ++#define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */ ++ ++/* size of brcmf_scan_params not including variable length array */ ++#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 ++ ++/* masks for channel and ssid count */ ++#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff ++#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 ++ ++#define BRCMF_SCAN_ACTION_START 1 ++#define BRCMF_SCAN_ACTION_CONTINUE 2 ++#define WL_SCAN_ACTION_ABORT 3 ++ ++#define BRCMF_ISCAN_REQ_VERSION 1 ++ ++/* brcmf_iscan_results status values */ ++#define BRCMF_SCAN_RESULTS_SUCCESS 0 ++#define BRCMF_SCAN_RESULTS_PARTIAL 1 ++#define BRCMF_SCAN_RESULTS_PENDING 2 ++#define BRCMF_SCAN_RESULTS_ABORTED 3 ++#define BRCMF_SCAN_RESULTS_NO_MEM 4 ++ ++/* Indicates this key is using soft encrypt */ ++#define WL_SOFT_KEY (1 << 0) ++/* primary (ie tx) key */ ++#define BRCMF_PRIMARY_KEY (1 << 1) ++/* Reserved for backward compat */ ++#define WL_KF_RES_4 (1 << 4) ++/* Reserved for backward compat */ ++#define WL_KF_RES_5 (1 << 5) ++/* Indicates a group key for a IBSS PEER */ ++#define WL_IBSS_PEER_GROUP_KEY (1 << 6) ++ ++/* For supporting multiple interfaces */ ++#define BRCMF_MAX_IFS 16 ++#define BRCMF_DEL_IF -0xe ++#define BRCMF_BAD_IF -0xf ++ ++#define DOT11_BSSTYPE_ANY 2 ++#define DOT11_MAX_DEFAULT_KEYS 4 ++ ++#define BRCMF_EVENT_MSG_LINK 0x01 ++#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 ++#define BRCMF_EVENT_MSG_GROUP 0x04 ++ ++struct brcmf_event_msg { ++ __be16 version; ++ __be16 flags; ++ __be32 event_type; ++ __be32 status; ++ __be32 reason; ++ __be32 auth_type; ++ __be32 datalen; ++ u8 addr[ETH_ALEN]; ++ char ifname[IFNAMSIZ]; ++} __packed; ++ ++struct brcm_ethhdr { ++ u16 subtype; ++ u16 length; ++ u8 version; ++ u8 oui[3]; ++ u16 usr_subtype; ++} __packed; ++ ++struct brcmf_event { ++ struct ethhdr eth; ++ struct brcm_ethhdr hdr; ++ struct brcmf_event_msg msg; ++} __packed; ++ ++struct dngl_stats { ++ unsigned long rx_packets; /* total packets received */ ++ unsigned long tx_packets; /* total packets transmitted */ ++ unsigned long rx_bytes; /* total bytes received */ ++ unsigned long tx_bytes; /* total bytes transmitted */ ++ unsigned long rx_errors; /* bad packets received */ ++ unsigned long tx_errors; /* packet transmit problems */ ++ unsigned long rx_dropped; /* packets dropped by dongle */ ++ unsigned long tx_dropped; /* packets dropped by dongle */ ++ unsigned long multicast; /* multicast packets received */ ++}; ++ ++/* event codes sent by the dongle to this driver */ ++#define BRCMF_E_SET_SSID 0 ++#define BRCMF_E_JOIN 1 ++#define BRCMF_E_START 2 ++#define BRCMF_E_AUTH 3 ++#define BRCMF_E_AUTH_IND 4 ++#define BRCMF_E_DEAUTH 5 ++#define BRCMF_E_DEAUTH_IND 6 ++#define BRCMF_E_ASSOC 7 ++#define BRCMF_E_ASSOC_IND 8 ++#define BRCMF_E_REASSOC 9 ++#define BRCMF_E_REASSOC_IND 10 ++#define BRCMF_E_DISASSOC 11 ++#define BRCMF_E_DISASSOC_IND 12 ++#define BRCMF_E_QUIET_START 13 ++#define BRCMF_E_QUIET_END 14 ++#define BRCMF_E_BEACON_RX 15 ++#define BRCMF_E_LINK 16 ++#define BRCMF_E_MIC_ERROR 17 ++#define BRCMF_E_NDIS_LINK 18 ++#define BRCMF_E_ROAM 19 ++#define BRCMF_E_TXFAIL 20 ++#define BRCMF_E_PMKID_CACHE 21 ++#define BRCMF_E_RETROGRADE_TSF 22 ++#define BRCMF_E_PRUNE 23 ++#define BRCMF_E_AUTOAUTH 24 ++#define BRCMF_E_EAPOL_MSG 25 ++#define BRCMF_E_SCAN_COMPLETE 26 ++#define BRCMF_E_ADDTS_IND 27 ++#define BRCMF_E_DELTS_IND 28 ++#define BRCMF_E_BCNSENT_IND 29 ++#define BRCMF_E_BCNRX_MSG 30 ++#define BRCMF_E_BCNLOST_MSG 31 ++#define BRCMF_E_ROAM_PREP 32 ++#define BRCMF_E_PFN_NET_FOUND 33 ++#define BRCMF_E_PFN_NET_LOST 34 ++#define BRCMF_E_RESET_COMPLETE 35 ++#define BRCMF_E_JOIN_START 36 ++#define BRCMF_E_ROAM_START 37 ++#define BRCMF_E_ASSOC_START 38 ++#define BRCMF_E_IBSS_ASSOC 39 ++#define BRCMF_E_RADIO 40 ++#define BRCMF_E_PSM_WATCHDOG 41 ++#define BRCMF_E_PROBREQ_MSG 44 ++#define BRCMF_E_SCAN_CONFIRM_IND 45 ++#define BRCMF_E_PSK_SUP 46 ++#define BRCMF_E_COUNTRY_CODE_CHANGED 47 ++#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48 ++#define BRCMF_E_ICV_ERROR 49 ++#define BRCMF_E_UNICAST_DECODE_ERROR 50 ++#define BRCMF_E_MULTICAST_DECODE_ERROR 51 ++#define BRCMF_E_TRACE 52 ++#define BRCMF_E_IF 54 ++#define BRCMF_E_RSSI 56 ++#define BRCMF_E_PFN_SCAN_COMPLETE 57 ++#define BRCMF_E_EXTLOG_MSG 58 ++#define BRCMF_E_ACTION_FRAME 59 ++#define BRCMF_E_ACTION_FRAME_COMPLETE 60 ++#define BRCMF_E_PRE_ASSOC_IND 61 ++#define BRCMF_E_PRE_REASSOC_IND 62 ++#define BRCMF_E_CHANNEL_ADOPTED 63 ++#define BRCMF_E_AP_STARTED 64 ++#define BRCMF_E_DFS_AP_STOP 65 ++#define BRCMF_E_DFS_AP_RESUME 66 ++#define BRCMF_E_RESERVED1 67 ++#define BRCMF_E_RESERVED2 68 ++#define BRCMF_E_ESCAN_RESULT 69 ++#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 ++#define BRCMF_E_DCS_REQUEST 73 ++ ++#define BRCMF_E_FIFO_CREDIT_MAP 74 ++ ++#define BRCMF_E_LAST 75 ++ ++#define BRCMF_E_STATUS_SUCCESS 0 ++#define BRCMF_E_STATUS_FAIL 1 ++#define BRCMF_E_STATUS_TIMEOUT 2 ++#define BRCMF_E_STATUS_NO_NETWORKS 3 ++#define BRCMF_E_STATUS_ABORT 4 ++#define BRCMF_E_STATUS_NO_ACK 5 ++#define BRCMF_E_STATUS_UNSOLICITED 6 ++#define BRCMF_E_STATUS_ATTEMPT 7 ++#define BRCMF_E_STATUS_PARTIAL 8 ++#define BRCMF_E_STATUS_NEWSCAN 9 ++#define BRCMF_E_STATUS_NEWASSOC 10 ++#define BRCMF_E_STATUS_11HQUIET 11 ++#define BRCMF_E_STATUS_SUPPRESS 12 ++#define BRCMF_E_STATUS_NOCHANS 13 ++#define BRCMF_E_STATUS_CS_ABORT 15 ++#define BRCMF_E_STATUS_ERROR 16 ++ ++#define BRCMF_E_REASON_INITIAL_ASSOC 0 ++#define BRCMF_E_REASON_LOW_RSSI 1 ++#define BRCMF_E_REASON_DEAUTH 2 ++#define BRCMF_E_REASON_DISASSOC 3 ++#define BRCMF_E_REASON_BCNS_LOST 4 ++#define BRCMF_E_REASON_MINTXRATE 9 ++#define BRCMF_E_REASON_TXFAIL 10 ++ ++#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 ++#define BRCMF_E_REASON_DIRECTED_ROAM 6 ++#define BRCMF_E_REASON_TSPEC_REJECTED 7 ++#define BRCMF_E_REASON_BETTER_AP 8 ++ ++#define BRCMF_E_PRUNE_ENCR_MISMATCH 1 ++#define BRCMF_E_PRUNE_BCAST_BSSID 2 ++#define BRCMF_E_PRUNE_MAC_DENY 3 ++#define BRCMF_E_PRUNE_MAC_NA 4 ++#define BRCMF_E_PRUNE_REG_PASSV 5 ++#define BRCMF_E_PRUNE_SPCT_MGMT 6 ++#define BRCMF_E_PRUNE_RADAR 7 ++#define BRCMF_E_RSN_MISMATCH 8 ++#define BRCMF_E_PRUNE_NO_COMMON_RATES 9 ++#define BRCMF_E_PRUNE_BASIC_RATES 10 ++#define BRCMF_E_PRUNE_CIPHER_NA 12 ++#define BRCMF_E_PRUNE_KNOWN_STA 13 ++#define BRCMF_E_PRUNE_WDS_PEER 15 ++#define BRCMF_E_PRUNE_QBSS_LOAD 16 ++#define BRCMF_E_PRUNE_HOME_AP 17 ++ ++#define BRCMF_E_SUP_OTHER 0 ++#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1 ++#define BRCMF_E_SUP_BAD_UCAST_WEP128 2 ++#define BRCMF_E_SUP_BAD_UCAST_WEP40 3 ++#define BRCMF_E_SUP_UNSUP_KEY_LEN 4 ++#define BRCMF_E_SUP_PW_KEY_CIPHER 5 ++#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6 ++#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7 ++#define BRCMF_E_SUP_NO_INSTALL_FLAG 8 ++#define BRCMF_E_SUP_MSG3_NO_GTK 9 ++#define BRCMF_E_SUP_GRP_KEY_CIPHER 10 ++#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11 ++#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12 ++#define BRCMF_E_SUP_SEND_FAIL 13 ++#define BRCMF_E_SUP_DEAUTH 14 ++ ++#define BRCMF_E_IF_ADD 1 ++#define BRCMF_E_IF_DEL 2 ++#define BRCMF_E_IF_CHANGE 3 ++ ++#define BRCMF_E_IF_ROLE_STA 0 ++#define BRCMF_E_IF_ROLE_AP 1 ++#define BRCMF_E_IF_ROLE_WDS 2 ++ ++#define BRCMF_E_LINK_BCN_LOSS 1 ++#define BRCMF_E_LINK_DISASSOC 2 ++#define BRCMF_E_LINK_ASSOC_REC 3 ++#define BRCMF_E_LINK_BSSCFG_DIS 4 ++ ++/* The level of bus communication with the dongle */ ++enum brcmf_bus_state { ++ BRCMF_BUS_DOWN, /* Not ready for frame transfers */ ++ BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ ++ BRCMF_BUS_DATA /* Ready for frame transfers */ ++}; ++ ++/* Pattern matching filter. Specifies an offset within received packets to ++ * start matching, the pattern to match, the size of the pattern, and a bitmask ++ * that indicates which bits within the pattern should be matched. ++ */ ++struct brcmf_pkt_filter_pattern_le { ++ /* ++ * Offset within received packet to start pattern matching. ++ * Offset '0' is the first byte of the ethernet header. ++ */ ++ __le32 offset; ++ /* Size of the pattern. Bitmask must be the same size.*/ ++ __le32 size_bytes; ++ /* ++ * Variable length mask and pattern data. mask starts at offset 0. ++ * Pattern immediately follows mask. ++ */ ++ u8 mask_and_pattern[1]; ++}; ++ ++/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ ++struct brcmf_pkt_filter_le { ++ __le32 id; /* Unique filter id, specified by app. */ ++ __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ ++ __le32 negate_match; /* Negate the result of filter matches */ ++ union { /* Filter definitions */ ++ struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ ++ } u; ++}; ++ ++/* IOVAR "pkt_filter_enable" parameter. */ ++struct brcmf_pkt_filter_enable_le { ++ __le32 id; /* Unique filter id */ ++ __le32 enable; /* Enable/disable bool */ ++}; ++ ++/* BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in struct brcmf_scan_results) ++ */ ++struct brcmf_bss_info { ++ __le32 version; /* version field */ ++ __le32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ u8 BSSID[ETH_ALEN]; ++ __le16 beacon_period; /* units are Kusec */ ++ __le16 capability; /* Capability information */ ++ u8 SSID_len; ++ u8 SSID[32]; ++ struct { ++ __le32 count; /* # rates in this set */ ++ u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ __le16 chanspec; /* chanspec for bss */ ++ __le16 atim_window; /* units are Kusec */ ++ u8 dtim_period; /* DTIM period */ ++ __le16 RSSI; /* receive signal strength (in dBm) */ ++ s8 phy_noise; /* noise (in dBm) */ ++ ++ u8 n_cap; /* BSS is 802.11N Capable */ ++ /* 802.11N BSS Capabilities (based on HT_CAP_*): */ ++ __le32 nbss_cap; ++ u8 ctl_ch; /* 802.11N BSS control channel number */ ++ __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ ++ u8 flags; /* flags */ ++ u8 reserved[3]; /* Reserved for expansion of BSS properties */ ++ u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ ++ __le16 ie_offset; /* offset at which IEs start, from beginning */ ++ __le32 ie_length; /* byte length of Information Elements */ ++ __le16 SNR; /* average SNR of during frame reception */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++}; ++ ++struct brcm_rateset_le { ++ /* # rates in this set */ ++ __le32 count; ++ /* rates in 500kbps units w/hi bit set if basic */ ++ u8 rates[WL_NUMRATES]; ++}; ++ ++struct brcmf_ssid { ++ u32 SSID_len; ++ unsigned char SSID[32]; ++}; ++ ++struct brcmf_ssid_le { ++ __le32 SSID_len; ++ unsigned char SSID[32]; ++}; ++ ++struct brcmf_scan_params_le { ++ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ ++ u8 bssid[ETH_ALEN]; /* default: bcast */ ++ s8 bss_type; /* default: any, ++ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT ++ */ ++ u8 scan_type; /* flags, 0 use default */ ++ __le32 nprobes; /* -1 use default, number of probes per channel */ ++ __le32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ __le32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ __le32 home_time; /* -1 use default, dwell time for the ++ * home channel between channel scans ++ */ ++ __le32 channel_num; /* count of channels and ssids that follow ++ * ++ * low half is count of channels in ++ * channel_list, 0 means default (use all ++ * available channels) ++ * ++ * high half is entries in struct brcmf_ssid ++ * array that follows channel_list, aligned for ++ * s32 (4 bytes) meaning an odd channel count ++ * implies a 2-byte pad between end of ++ * channel_list and first ssid ++ * ++ * if ssid count is zero, single ssid in the ++ * fixed parameter portion is assumed, otherwise ++ * ssid in the fixed portion is ignored ++ */ ++ __le16 channel_list[1]; /* list of chanspecs */ ++}; ++ ++/* incremental scan struct */ ++struct brcmf_iscan_params_le { ++ __le32 version; ++ __le16 action; ++ __le16 scan_duration; ++ struct brcmf_scan_params_le params_le; ++}; ++ ++struct brcmf_scan_results { ++ u32 buflen; ++ u32 version; ++ u32 count; ++ struct brcmf_bss_info bss_info[1]; ++}; ++ ++struct brcmf_scan_results_le { ++ __le32 buflen; ++ __le32 version; ++ __le32 count; ++ struct brcmf_bss_info bss_info[1]; ++}; ++ ++/* used for association with a specific BSSID and chanspec list */ ++struct brcmf_assoc_params_le { ++ /* 00:00:00:00:00:00: broadcast scan */ ++ u8 bssid[ETH_ALEN]; ++ /* 0: all available channels, otherwise count of chanspecs in ++ * chanspec_list */ ++ __le32 chanspec_num; ++ /* list of chanspecs */ ++ __le16 chanspec_list[1]; ++}; ++ ++/* used for join with or without a specific bssid and channel list */ ++struct brcmf_join_params { ++ struct brcmf_ssid_le ssid_le; ++ struct brcmf_assoc_params_le params_le; ++}; ++ ++/* size of brcmf_scan_results not including variable length array */ ++#define BRCMF_SCAN_RESULTS_FIXED_SIZE \ ++ (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info)) ++ ++/* incremental scan results struct */ ++struct brcmf_iscan_results { ++ union { ++ u32 status; ++ __le32 status_le; ++ }; ++ union { ++ struct brcmf_scan_results results; ++ struct brcmf_scan_results_le results_le; ++ }; ++}; ++ ++/* size of brcmf_iscan_results not including variable length array */ ++#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \ ++ (BRCMF_SCAN_RESULTS_FIXED_SIZE + \ ++ offsetof(struct brcmf_iscan_results, results)) ++ ++struct brcmf_wsec_key { ++ u32 index; /* key index */ ++ u32 len; /* key length */ ++ u8 data[WLAN_MAX_KEY_LEN]; /* key data */ ++ u32 pad_1[18]; ++ u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ ++ u32 flags; /* misc flags */ ++ u32 pad_2[3]; ++ u32 iv_initialized; /* has IV been initialized already? */ ++ u32 pad_3; ++ /* Rx IV */ ++ struct { ++ u32 hi; /* upper 32 bits of IV */ ++ u16 lo; /* lower 16 bits of IV */ ++ } rxiv; ++ u32 pad_4[2]; ++ u8 ea[ETH_ALEN]; /* per station */ ++}; ++ ++/* ++ * dongle requires same struct as above but with fields in little endian order ++ */ ++struct brcmf_wsec_key_le { ++ __le32 index; /* key index */ ++ __le32 len; /* key length */ ++ u8 data[WLAN_MAX_KEY_LEN]; /* key data */ ++ __le32 pad_1[18]; ++ __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ ++ __le32 flags; /* misc flags */ ++ __le32 pad_2[3]; ++ __le32 iv_initialized; /* has IV been initialized already? */ ++ __le32 pad_3; ++ /* Rx IV */ ++ struct { ++ __le32 hi; /* upper 32 bits of IV */ ++ __le16 lo; /* lower 16 bits of IV */ ++ } rxiv; ++ __le32 pad_4[2]; ++ u8 ea[ETH_ALEN]; /* per station */ ++}; ++ ++/* Used to get specific STA parameters */ ++struct brcmf_scb_val_le { ++ __le32 val; ++ u8 ea[ETH_ALEN]; ++}; ++ ++/* channel encoding */ ++struct brcmf_channel_info_le { ++ __le32 hw_channel; ++ __le32 target_channel; ++ __le32 scan_channel; ++}; ++ ++/* Bus independent dongle command */ ++struct brcmf_dcmd { ++ uint cmd; /* common dongle cmd definition */ ++ void *buf; /* pointer to user buffer */ ++ uint len; /* length of user buffer */ ++ u8 set; /* get or set request (optional) */ ++ uint used; /* bytes read or written (optional) */ ++ uint needed; /* bytes needed (optional) */ ++}; ++ ++/* Forward decls for struct brcmf_pub (see below) */ ++struct brcmf_bus; /* device bus info */ ++struct brcmf_proto; /* device communication protocol info */ ++struct brcmf_info; /* device driver info */ ++struct brcmf_cfg80211_dev; /* cfg80211 device info */ ++ ++/* Common structure for module and instance linkage */ ++struct brcmf_pub { ++ /* Linkage ponters */ ++ struct brcmf_bus *bus; ++ struct brcmf_proto *prot; ++ struct brcmf_info *info; ++ struct brcmf_cfg80211_dev *config; ++ ++ /* Internal brcmf items */ ++ bool up; /* Driver up/down (to OS) */ ++ bool txoff; /* Transmit flow-controlled */ ++ enum brcmf_bus_state busstate; ++ uint hdrlen; /* Total BRCMF header length (proto + bus) */ ++ uint maxctl; /* Max size rxctl request from proto to bus */ ++ uint rxsz; /* Rx buffer size bus module should use */ ++ u8 wme_dp; /* wme discard priority */ ++ ++ /* Dongle media info */ ++ bool iswl; /* Dongle-resident driver is wl */ ++ unsigned long drv_version; /* Version of dongle-resident driver */ ++ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ ++ struct dngl_stats dstats; /* Stats for dongle-based data */ ++ ++ /* Additional stats for the bus level */ ++ ++ /* Data packets sent to dongle */ ++ unsigned long tx_packets; ++ /* Multicast data packets sent to dongle */ ++ unsigned long tx_multicast; ++ /* Errors in sending data to dongle */ ++ unsigned long tx_errors; ++ /* Control packets sent to dongle */ ++ unsigned long tx_ctlpkts; ++ /* Errors sending control frames to dongle */ ++ unsigned long tx_ctlerrs; ++ /* Packets sent up the network interface */ ++ unsigned long rx_packets; ++ /* Multicast packets sent up the network interface */ ++ unsigned long rx_multicast; ++ /* Errors processing rx data packets */ ++ unsigned long rx_errors; ++ /* Control frames processed from dongle */ ++ unsigned long rx_ctlpkts; ++ ++ /* Errors in processing rx control frames */ ++ unsigned long rx_ctlerrs; ++ /* Packets dropped locally (no memory) */ ++ unsigned long rx_dropped; ++ /* Packets flushed due to unscheduled sendup thread */ ++ unsigned long rx_flushed; ++ /* Number of times dpc scheduled by watchdog timer */ ++ unsigned long wd_dpc_sched; ++ ++ /* Number of packets where header read-ahead was used. */ ++ unsigned long rx_readahead_cnt; ++ /* Number of tx packets we had to realloc for headroom */ ++ unsigned long tx_realloc; ++ /* Number of flow control pkts recvd */ ++ unsigned long fc_packets; ++ ++ /* Last error return */ ++ int bcmerror; ++ uint tickcnt; ++ ++ /* Last error from dongle */ ++ int dongle_error; ++ ++ /* Suspend disable flag flag */ ++ int suspend_disable_flag; /* "1" to disable all extra powersaving ++ during suspend */ ++ int in_suspend; /* flag set to 1 when early suspend called */ ++ int dtim_skip; /* dtim skip , default 0 means wake each dtim */ ++ ++ /* Pkt filter defination */ ++ char *pktfilter[100]; ++ int pktfilter_count; ++ ++ u8 country_code[BRCM_CNTRY_BUF_SZ]; ++ char eventmask[BRCMF_EVENTING_MASK_LEN]; ++ ++}; ++ ++struct brcmf_if_event { ++ u8 ifidx; ++ u8 action; ++ u8 flags; ++ u8 bssidx; ++}; ++ ++struct bcmevent_name { ++ uint event; ++ const char *name; ++}; ++ ++extern const struct bcmevent_name bcmevent_names[]; ++ ++extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, ++ char *buf, uint len); ++ ++/* Indication from bus module regarding presence/insertion of dongle. ++ * Return struct brcmf_pub pointer, used as handle to OS module in later calls. ++ * Returned structure should have bus and prot pointers filled in. ++ * bus_hdrlen specifies required headroom for bus module header. ++ */ ++extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, ++ uint bus_hdrlen); ++extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); ++extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); ++ ++extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len); ++ ++/* Indication from bus module regarding removal/absence of dongle */ ++extern void brcmf_detach(struct brcmf_pub *drvr); ++ ++/* Indication from bus module to change flow-control state */ ++extern void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool on); ++ ++extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, ++ struct sk_buff *pkt, int prec); ++ ++/* Receive frame for delivery to OS. Callee disposes of rxp. */ ++extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, ++ struct sk_buff *rxp, int numpkt); ++ ++/* Return pointer to interface name */ ++extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); ++ ++/* Notify tx completion */ ++extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, ++ bool success); ++ ++/* Query dongle */ ++extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, ++ uint cmd, void *buf, uint len); ++ ++/* OS independent layer functions */ ++extern int brcmf_os_proto_block(struct brcmf_pub *drvr); ++extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr); ++#ifdef BCMDBG ++extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size); ++#endif /* BCMDBG */ ++ ++extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name); ++extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx, ++ void *pktdata, struct brcmf_event_msg *, ++ void **data_ptr); ++ ++extern void brcmf_c_init(void); ++ ++extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, ++ struct net_device *ndev, char *name, u8 *mac_addr, ++ u32 flags, u8 bssidx); ++extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); ++ ++/* Send packet to dongle via data channel */ ++extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ ++ struct sk_buff *pkt); ++ ++extern int brcmf_bus_start(struct brcmf_pub *drvr); ++ ++extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); ++extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, ++ int enable, int master_mode); ++ ++#define BRCMF_DCMD_SMLEN 256 /* "small" cmd buffer required */ ++#define BRCMF_DCMD_MEDLEN 1536 /* "med" cmd buffer required */ ++#define BRCMF_DCMD_MAXLEN 8192 /* max length cmd buffer required */ ++ ++/* message levels */ ++#define BRCMF_ERROR_VAL 0x0001 ++#define BRCMF_TRACE_VAL 0x0002 ++#define BRCMF_INFO_VAL 0x0004 ++#define BRCMF_DATA_VAL 0x0008 ++#define BRCMF_CTL_VAL 0x0010 ++#define BRCMF_TIMER_VAL 0x0020 ++#define BRCMF_HDRS_VAL 0x0040 ++#define BRCMF_BYTES_VAL 0x0080 ++#define BRCMF_INTR_VAL 0x0100 ++#define BRCMF_GLOM_VAL 0x0400 ++#define BRCMF_EVENT_VAL 0x0800 ++#define BRCMF_BTA_VAL 0x1000 ++#define BRCMF_ISCAN_VAL 0x2000 ++ ++/* Enter idle immediately (no timeout) */ ++#define BRCMF_IDLE_IMMEDIATE (-1) ++#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change ++ when idle */ ++#define BRCMF_IDLE_INTERVAL 1 ++ ++#endif /* _BRCMF_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c.orig 2011-11-09 13:46:58.232800795 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c 2011-11-09 13:47:16.983566378 -0500 +@@ -0,0 +1,1356 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dhd.h" ++#include "dhd_bus.h" ++#include "dhd_proto.h" ++#include "dhd_dbg.h" ++#include "wl_cfg80211.h" ++#include "bcmchip.h" ++ ++MODULE_AUTHOR("Broadcom Corporation"); ++MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); ++MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++ ++/* Interface control information */ ++struct brcmf_if { ++ struct brcmf_info *info; /* back pointer to brcmf_info */ ++ /* OS/stack specifics */ ++ struct net_device *ndev; ++ struct net_device_stats stats; ++ int idx; /* iface idx in dongle */ ++ int state; /* interface state */ ++ u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ ++}; ++ ++/* Local private structure (extension of pub) */ ++struct brcmf_info { ++ struct brcmf_pub pub; ++ ++ /* OS/stack specifics */ ++ struct brcmf_if *iflist[BRCMF_MAX_IFS]; ++ ++ struct mutex proto_block; ++ ++ struct work_struct setmacaddr_work; ++ struct work_struct multicast_work; ++ u8 macvalue[ETH_ALEN]; ++ atomic_t pend_8021x_cnt; ++}; ++ ++/* Error bits */ ++module_param(brcmf_msg_level, int, 0); ++ ++ ++static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev) ++{ ++ int i = 0; ++ ++ while (i < BRCMF_MAX_IFS) { ++ if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev) ++ return i; ++ i++; ++ } ++ ++ return BRCMF_BAD_IF; ++} ++ ++int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) ++{ ++ int i = BRCMF_MAX_IFS; ++ struct brcmf_if *ifp; ++ ++ if (name == NULL || *name == '\0') ++ return 0; ++ ++ while (--i > 0) { ++ ifp = drvr_priv->iflist[i]; ++ if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ)) ++ break; ++ } ++ ++ brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name); ++ ++ return i; /* default - the primary interface */ ++} ++ ++char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ ++ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { ++ brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx); ++ return ""; ++ } ++ ++ if (drvr_priv->iflist[ifidx] == NULL) { ++ brcmf_dbg(ERROR, "null i/f %d\n", ifidx); ++ return ""; ++ } ++ ++ if (drvr_priv->iflist[ifidx]->ndev) ++ return drvr_priv->iflist[ifidx]->ndev->name; ++ ++ return ""; ++} ++ ++static void _brcmf_set_multicast_list(struct work_struct *work) ++{ ++ struct net_device *ndev; ++ struct netdev_hw_addr *ha; ++ u32 dcmd_value, cnt; ++ __le32 cnt_le; ++ __le32 dcmd_le_value; ++ ++ struct brcmf_dcmd dcmd; ++ char *buf, *bufp; ++ uint buflen; ++ int ret; ++ ++ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, ++ multicast_work); ++ ++ ndev = drvr_priv->iflist[0]->ndev; ++ cnt = netdev_mc_count(ndev); ++ ++ /* Determine initial value of allmulti flag */ ++ dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false; ++ ++ /* Send down the multicast list first. */ ++ ++ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); ++ bufp = buf = kmalloc(buflen, GFP_ATOMIC); ++ if (!bufp) ++ return; ++ ++ strcpy(bufp, "mcast_list"); ++ bufp += strlen("mcast_list") + 1; ++ ++ cnt_le = cpu_to_le32(cnt); ++ memcpy(bufp, &cnt_le, sizeof(cnt)); ++ bufp += sizeof(cnt_le); ++ ++ netdev_for_each_mc_addr(ha, ndev) { ++ if (!cnt) ++ break; ++ memcpy(bufp, ha->addr, ETH_ALEN); ++ bufp += ETH_ALEN; ++ cnt--; ++ } ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ dcmd.cmd = BRCMF_C_SET_VAR; ++ dcmd.buf = buf; ++ dcmd.len = buflen; ++ dcmd.set = true; ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n", ++ brcmf_ifname(&drvr_priv->pub, 0), cnt); ++ dcmd_value = cnt ? true : dcmd_value; ++ } ++ ++ kfree(buf); ++ ++ /* Now send the allmulti setting. This is based on the setting in the ++ * net_device flags, but might be modified above to be turned on if we ++ * were trying to set some addresses and dongle rejected it... ++ */ ++ ++ buflen = sizeof("allmulti") + sizeof(dcmd_value); ++ buf = kmalloc(buflen, GFP_ATOMIC); ++ if (!buf) ++ return; ++ ++ dcmd_le_value = cpu_to_le32(dcmd_value); ++ ++ if (!brcmf_c_mkiovar ++ ("allmulti", (void *)&dcmd_le_value, ++ sizeof(dcmd_le_value), buf, buflen)) { ++ brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n", ++ brcmf_ifname(&drvr_priv->pub, 0), ++ (int)sizeof(dcmd_value), buflen); ++ kfree(buf); ++ return; ++ } ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ dcmd.cmd = BRCMF_C_SET_VAR; ++ dcmd.buf = buf; ++ dcmd.len = buflen; ++ dcmd.set = true; ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "%s: set allmulti %d failed\n", ++ brcmf_ifname(&drvr_priv->pub, 0), ++ le32_to_cpu(dcmd_le_value)); ++ } ++ ++ kfree(buf); ++ ++ /* Finally, pick up the PROMISC flag as well, like the NIC ++ driver does */ ++ ++ dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false; ++ dcmd_le_value = cpu_to_le32(dcmd_value); ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ dcmd.cmd = BRCMF_C_SET_PROMISC; ++ dcmd.buf = &dcmd_le_value; ++ dcmd.len = sizeof(dcmd_le_value); ++ dcmd.set = true; ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "%s: set promisc %d failed\n", ++ brcmf_ifname(&drvr_priv->pub, 0), ++ le32_to_cpu(dcmd_le_value)); ++ } ++} ++ ++static void ++_brcmf_set_mac_address(struct work_struct *work) ++{ ++ char buf[32]; ++ struct brcmf_dcmd dcmd; ++ int ret; ++ ++ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, ++ setmacaddr_work); ++ ++ brcmf_dbg(TRACE, "enter\n"); ++ if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue, ++ ETH_ALEN, buf, 32)) { ++ brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n", ++ brcmf_ifname(&drvr_priv->pub, 0)); ++ return; ++ } ++ memset(&dcmd, 0, sizeof(dcmd)); ++ dcmd.cmd = BRCMF_C_SET_VAR; ++ dcmd.buf = buf; ++ dcmd.len = 32; ++ dcmd.set = true; ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); ++ if (ret < 0) ++ brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n", ++ brcmf_ifname(&drvr_priv->pub, 0)); ++ else ++ memcpy(drvr_priv->iflist[0]->ndev->dev_addr, ++ drvr_priv->macvalue, ETH_ALEN); ++ ++ return; ++} ++ ++static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ struct sockaddr *sa = (struct sockaddr *)addr; ++ int ifidx; ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ if (ifidx == BRCMF_BAD_IF) ++ return -1; ++ ++ memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); ++ schedule_work(&drvr_priv->setmacaddr_work); ++ return 0; ++} ++ ++static void brcmf_netdev_set_multicast_list(struct net_device *ndev) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ int ifidx; ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ if (ifidx == BRCMF_BAD_IF) ++ return; ++ ++ schedule_work(&drvr_priv->multicast_work); ++} ++ ++int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ ++ /* Reject if down */ ++ if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) ++ return -ENODEV; ++ ++ /* Update multicast statistic */ ++ if (pktbuf->len >= ETH_ALEN) { ++ u8 *pktdata = (u8 *) (pktbuf->data); ++ struct ethhdr *eh = (struct ethhdr *)pktdata; ++ ++ if (is_multicast_ether_addr(eh->h_dest)) ++ drvr->tx_multicast++; ++ if (ntohs(eh->h_proto) == ETH_P_PAE) ++ atomic_inc(&drvr_priv->pend_8021x_cnt); ++ } ++ ++ /* If the protocol uses a data header, apply it */ ++ brcmf_proto_hdrpush(drvr, ifidx, pktbuf); ++ ++ /* Use bus module to send data frame */ ++ return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); ++} ++ ++static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int ret; ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ int ifidx; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Reject if down */ ++ if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { ++ brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", ++ drvr_priv->pub.up, drvr_priv->pub.busstate); ++ netif_stop_queue(ndev); ++ return -ENODEV; ++ } ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ if (ifidx == BRCMF_BAD_IF) { ++ brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx); ++ netif_stop_queue(ndev); ++ return -ENODEV; ++ } ++ ++ /* Make sure there's enough room for any header */ ++ if (skb_headroom(skb) < drvr_priv->pub.hdrlen) { ++ struct sk_buff *skb2; ++ ++ brcmf_dbg(INFO, "%s: insufficient headroom\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx)); ++ drvr_priv->pub.tx_realloc++; ++ skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); ++ dev_kfree_skb(skb); ++ skb = skb2; ++ if (skb == NULL) { ++ brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx)); ++ ret = -ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); ++ ++done: ++ if (ret) ++ drvr_priv->pub.dstats.tx_dropped++; ++ else ++ drvr_priv->pub.tx_packets++; ++ ++ /* Return ok: we always eat the packet */ ++ return 0; ++} ++ ++void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state) ++{ ++ struct net_device *ndev; ++ struct brcmf_info *drvr_priv = drvr->info; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ drvr->txoff = state; ++ ndev = drvr_priv->iflist[ifidx]->ndev; ++ if (state == ON) ++ netif_stop_queue(ndev); ++ else ++ netif_wake_queue(ndev); ++} ++ ++static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, ++ void *pktdata, struct brcmf_event_msg *event, ++ void **data) ++{ ++ int bcmerror = 0; ++ ++ bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data); ++ if (bcmerror != 0) ++ return bcmerror; ++ ++ if (drvr_priv->iflist[*ifidx]->ndev) ++ brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev, ++ event, *data); ++ ++ return bcmerror; ++} ++ ++void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, ++ int numpkt) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ unsigned char *eth; ++ uint len; ++ void *data; ++ struct sk_buff *pnext, *save_pktbuf; ++ int i; ++ struct brcmf_if *ifp; ++ struct brcmf_event_msg event; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ save_pktbuf = skb; ++ ++ for (i = 0; skb && i < numpkt; i++, skb = pnext) { ++ ++ pnext = skb->next; ++ skb->next = NULL; ++ ++ /* Get the protocol, maintain skb around eth_type_trans() ++ * The main reason for this hack is for the limitation of ++ * Linux 2.4 where 'eth_type_trans' uses the ++ * 'net->hard_header_len' ++ * to perform skb_pull inside vs ETH_HLEN. Since to avoid ++ * coping of the packet coming from the network stack to add ++ * BDC, Hardware header etc, during network interface ++ * registration ++ * we set the 'net->hard_header_len' to ETH_HLEN + extra space ++ * required ++ * for BDC, Hardware header etc. and not just the ETH_HLEN ++ */ ++ eth = skb->data; ++ len = skb->len; ++ ++ ifp = drvr_priv->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = drvr_priv->iflist[0]; ++ ++ skb->dev = ifp->ndev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ if (skb->pkt_type == PACKET_MULTICAST) ++ drvr_priv->pub.rx_multicast++; ++ ++ skb->data = eth; ++ skb->len = len; ++ ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Process special event packets and then discard them */ ++ if (ntohs(skb->protocol) == ETH_P_LINK_CTL) ++ brcmf_host_event(drvr_priv, &ifidx, ++ skb_mac_header(skb), ++ &event, &data); ++ ++ if (drvr_priv->iflist[ifidx] && ++ !drvr_priv->iflist[ifidx]->state) ++ ifp = drvr_priv->iflist[ifidx]; ++ ++ if (ifp->ndev) ++ ifp->ndev->last_rx = jiffies; ++ ++ drvr->dstats.rx_bytes += skb->len; ++ drvr->rx_packets++; /* Local count */ ++ ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ /* If the receive is not processed inside an ISR, ++ * the softirqd must be woken explicitly to service ++ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++ netif_rx_ni(skb); ++ } ++} ++ ++void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success) ++{ ++ uint ifidx; ++ struct brcmf_info *drvr_priv = drvr->info; ++ struct ethhdr *eh; ++ u16 type; ++ ++ brcmf_proto_hdrpull(drvr, &ifidx, txp); ++ ++ eh = (struct ethhdr *)(txp->data); ++ type = ntohs(eh->h_proto); ++ ++ if (type == ETH_P_PAE) ++ atomic_dec(&drvr_priv->pend_8021x_cnt); ++ ++} ++ ++static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ struct brcmf_if *ifp; ++ int ifidx; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ if (ifidx == BRCMF_BAD_IF) ++ return NULL; ++ ++ ifp = drvr_priv->iflist[ifidx]; ++ ++ if (drvr_priv->pub.up) ++ /* Use the protocol to get dongle stats */ ++ brcmf_proto_dstats(&drvr_priv->pub); ++ ++ /* Copy dongle stats to net device stats */ ++ ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets; ++ ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets; ++ ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes; ++ ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes; ++ ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors; ++ ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors; ++ ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped; ++ ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped; ++ ifp->stats.multicast = drvr_priv->pub.dstats.multicast; ++ ++ return &ifp->stats; ++} ++ ++/* Retrieve current toe component enables, which are kept ++ as a bitmap in toe_ol iovar */ ++static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol) ++{ ++ struct brcmf_dcmd dcmd; ++ __le32 toe_le; ++ char buf[32]; ++ int ret; ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ ++ dcmd.cmd = BRCMF_C_GET_VAR; ++ dcmd.buf = buf; ++ dcmd.len = (uint) sizeof(buf); ++ dcmd.set = false; ++ ++ strcpy(buf, "toe_ol"); ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); ++ if (ret < 0) { ++ /* Check for older dongle image that doesn't support toe_ol */ ++ if (ret == -EIO) { ++ brcmf_dbg(ERROR, "%s: toe not supported by device\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx)); ++ return -EOPNOTSUPP; ++ } ++ ++ brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx), ret); ++ return ret; ++ } ++ ++ memcpy(&toe_le, buf, sizeof(u32)); ++ *toe_ol = le32_to_cpu(toe_le); ++ return 0; ++} ++ ++/* Set current toe component enables in toe_ol iovar, ++ and set toe global enable iovar */ ++static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol) ++{ ++ struct brcmf_dcmd dcmd; ++ char buf[32]; ++ int ret; ++ __le32 toe_le = cpu_to_le32(toe_ol); ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ ++ dcmd.cmd = BRCMF_C_SET_VAR; ++ dcmd.buf = buf; ++ dcmd.len = (uint) sizeof(buf); ++ dcmd.set = true; ++ ++ /* Set toe_ol as requested */ ++ strcpy(buf, "toe_ol"); ++ memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32)); ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx), ret); ++ return ret; ++ } ++ ++ /* Enable toe globally only if any components are enabled. */ ++ toe_le = cpu_to_le32(toe_ol != 0); ++ ++ strcpy(buf, "toe"); ++ memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32)); ++ ++ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); ++ if (ret < 0) { ++ brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n", ++ brcmf_ifname(&drvr_priv->pub, ifidx), ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, ++ struct ethtool_drvinfo *info) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ ++ sprintf(info->driver, KBUILD_MODNAME); ++ sprintf(info->version, "%lu", drvr_priv->pub.drv_version); ++ sprintf(info->fw_version, "%s", BCM4329_FW_NAME); ++ sprintf(info->bus_info, "%s", ++ dev_name(brcmf_bus_get_device(drvr_priv->pub.bus))); ++} ++ ++static struct ethtool_ops brcmf_ethtool_ops = { ++ .get_drvinfo = brcmf_ethtool_get_drvinfo ++}; ++ ++static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr) ++{ ++ struct ethtool_drvinfo info; ++ char drvname[sizeof(info.driver)]; ++ u32 cmd; ++ struct ethtool_value edata; ++ u32 toe_cmpnt, csum_dir; ++ int ret; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* all ethtool calls start with a cmd word */ ++ if (copy_from_user(&cmd, uaddr, sizeof(u32))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GDRVINFO: ++ /* Copy out any request driver name */ ++ if (copy_from_user(&info, uaddr, sizeof(info))) ++ return -EFAULT; ++ strncpy(drvname, info.driver, sizeof(info.driver)); ++ drvname[sizeof(info.driver) - 1] = '\0'; ++ ++ /* clear struct for return */ ++ memset(&info, 0, sizeof(info)); ++ info.cmd = cmd; ++ ++ /* if requested, identify ourselves */ ++ if (strcmp(drvname, "?dhd") == 0) { ++ sprintf(info.driver, "dhd"); ++ strcpy(info.version, BRCMF_VERSION_STR); ++ } ++ ++ /* otherwise, require dongle to be up */ ++ else if (!drvr_priv->pub.up) { ++ brcmf_dbg(ERROR, "dongle is not up\n"); ++ return -ENODEV; ++ } ++ ++ /* finally, report dongle driver type */ ++ else if (drvr_priv->pub.iswl) ++ sprintf(info.driver, "wl"); ++ else ++ sprintf(info.driver, "xx"); ++ ++ sprintf(info.version, "%lu", drvr_priv->pub.drv_version); ++ if (copy_to_user(uaddr, &info, sizeof(info))) ++ return -EFAULT; ++ brcmf_dbg(CTL, "given %*s, returning %s\n", ++ (int)sizeof(drvname), drvname, info.driver); ++ break; ++ ++ /* Get toe offload components from dongle */ ++ case ETHTOOL_GRXCSUM: ++ case ETHTOOL_GTXCSUM: ++ ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); ++ if (ret < 0) ++ return ret; ++ ++ csum_dir = ++ (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ edata.cmd = cmd; ++ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; ++ ++ if (copy_to_user(uaddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ break; ++ ++ /* Set toe offload components in dongle */ ++ case ETHTOOL_SRXCSUM: ++ case ETHTOOL_STXCSUM: ++ if (copy_from_user(&edata, uaddr, sizeof(edata))) ++ return -EFAULT; ++ ++ /* Read the current settings, update and write back */ ++ ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); ++ if (ret < 0) ++ return ret; ++ ++ csum_dir = ++ (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ if (edata.data != 0) ++ toe_cmpnt |= csum_dir; ++ else ++ toe_cmpnt &= ~csum_dir; ++ ++ ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt); ++ if (ret < 0) ++ return ret; ++ ++ /* If setting TX checksum mode, tell Linux the new mode */ ++ if (cmd == ETHTOOL_STXCSUM) { ++ if (edata.data) ++ drvr_priv->iflist[0]->ndev->features |= ++ NETIF_F_IP_CSUM; ++ else ++ drvr_priv->iflist[0]->ndev->features &= ++ ~NETIF_F_IP_CSUM; ++ } ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, ++ int cmd) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ int ifidx; ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd); ++ ++ if (ifidx == BRCMF_BAD_IF) ++ return -1; ++ ++ if (cmd == SIOCETHTOOL) ++ return brcmf_ethtool(drvr_priv, ifr->ifr_data); ++ ++ return -EOPNOTSUPP; ++} ++ ++/* called only from within this driver. Sends a command to the dongle. */ ++s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) ++{ ++ struct brcmf_dcmd dcmd; ++ s32 err = 0; ++ int buflen = 0; ++ bool is_set_key_cmd; ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ int ifidx; ++ ++ memset(&dcmd, 0, sizeof(dcmd)); ++ dcmd.cmd = cmd; ++ dcmd.buf = arg; ++ dcmd.len = len; ++ ++ ifidx = brcmf_net2idx(drvr_priv, ndev); ++ ++ if (dcmd.buf != NULL) ++ buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); ++ ++ /* send to dongle (must be up, and wl) */ ++ if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { ++ brcmf_dbg(ERROR, "DONGLE_DOWN\n"); ++ err = -EIO; ++ goto done; ++ } ++ ++ if (!drvr_priv->pub.iswl) { ++ err = -EIO; ++ goto done; ++ } ++ ++ /* ++ * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and ++ * set key CMD to prevent M4 encryption. ++ */ ++ is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) || ++ ((dcmd.cmd == BRCMF_C_SET_VAR) && ++ !(strncmp("wsec_key", dcmd.buf, 9))) || ++ ((dcmd.cmd == BRCMF_C_SET_VAR) && ++ !(strncmp("bsscfg:wsec_key", dcmd.buf, 15)))); ++ if (is_set_key_cmd) ++ brcmf_netdev_wait_pend8021x(ndev); ++ ++ err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen); ++ ++done: ++ if (err > 0) ++ err = 0; ++ ++ return err; ++} ++ ++static int brcmf_netdev_stop(struct net_device *ndev) ++{ ++ struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev); ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_cfg80211_down(drvr->config); ++ if (drvr->up == 0) ++ return 0; ++ ++ /* Set state and stop OS transmissions */ ++ drvr->up = 0; ++ netif_stop_queue(ndev); ++ ++ return 0; ++} ++ ++static int brcmf_netdev_open(struct net_device *ndev) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **) ++ netdev_priv(ndev); ++ u32 toe_ol; ++ int ifidx = brcmf_net2idx(drvr_priv, ndev); ++ s32 ret = 0; ++ ++ brcmf_dbg(TRACE, "ifidx %d\n", ifidx); ++ ++ if (ifidx == 0) { /* do it only for primary eth0 */ ++ ++ /* try to bring up bus */ ++ ret = brcmf_bus_start(&drvr_priv->pub); ++ if (ret != 0) { ++ brcmf_dbg(ERROR, "failed with code %d\n", ret); ++ return -1; ++ } ++ atomic_set(&drvr_priv->pend_8021x_cnt, 0); ++ ++ memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN); ++ ++ /* Get current TOE mode from dongle */ ++ if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 ++ && (toe_ol & TOE_TX_CSUM_OL) != 0) ++ drvr_priv->iflist[ifidx]->ndev->features |= ++ NETIF_F_IP_CSUM; ++ else ++ drvr_priv->iflist[ifidx]->ndev->features &= ++ ~NETIF_F_IP_CSUM; ++ } ++ /* Allow transmit calls */ ++ netif_start_queue(ndev); ++ drvr_priv->pub.up = 1; ++ if (brcmf_cfg80211_up(drvr_priv->pub.config)) { ++ brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++int ++brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, ++ char *name, u8 *mac_addr, u32 flags, u8 bssidx) ++{ ++ struct brcmf_if *ifp; ++ int ret = 0, err = 0; ++ ++ brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev); ++ ++ ifp = drvr_priv->iflist[ifidx]; ++ if (!ifp) { ++ ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); ++ if (!ifp) ++ return -ENOMEM; ++ } ++ ++ memset(ifp, 0, sizeof(struct brcmf_if)); ++ ifp->info = drvr_priv; ++ drvr_priv->iflist[ifidx] = ifp; ++ if (mac_addr != NULL) ++ memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); ++ ++ if (ndev == NULL) { ++ ifp->state = BRCMF_E_IF_ADD; ++ ifp->idx = ifidx; ++ /* ++ * Delete the existing interface before overwriting it ++ * in case we missed the BRCMF_E_IF_DEL event. ++ */ ++ if (ifp->ndev != NULL) { ++ brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", ++ ifp->ndev->name); ++ netif_stop_queue(ifp->ndev); ++ unregister_netdev(ifp->ndev); ++ free_netdev(ifp->ndev); ++ } ++ ++ /* Allocate netdev, including space for private structure */ ++ ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ++ ether_setup); ++ if (!ifp->ndev) { ++ brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); ++ ret = -ENOMEM; ++ } ++ ++ if (ret == 0) { ++ memcpy(netdev_priv(ifp->ndev), &drvr_priv, ++ sizeof(drvr_priv)); ++ err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); ++ if (err != 0) { ++ brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n", ++ err); ++ ret = -EOPNOTSUPP; ++ } else { ++ brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", ++ current->pid, ifp->ndev->name); ++ ifp->state = 0; ++ } ++ } ++ ++ if (ret < 0) { ++ if (ifp->ndev) ++ free_netdev(ifp->ndev); ++ ++ drvr_priv->iflist[ifp->idx] = NULL; ++ kfree(ifp); ++ } ++ } else ++ ifp->ndev = ndev; ++ ++ return 0; ++} ++ ++void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) ++{ ++ struct brcmf_if *ifp; ++ ++ brcmf_dbg(TRACE, "idx %d\n", ifidx); ++ ++ ifp = drvr_priv->iflist[ifidx]; ++ if (!ifp) { ++ brcmf_dbg(ERROR, "Null interface\n"); ++ return; ++ } ++ ++ ifp->state = BRCMF_E_IF_DEL; ++ ifp->idx = ifidx; ++ if (ifp->ndev != NULL) { ++ netif_stop_queue(ifp->ndev); ++ unregister_netdev(ifp->ndev); ++ free_netdev(ifp->ndev); ++ drvr_priv->iflist[ifidx] = NULL; ++ kfree(ifp); ++ } ++} ++ ++struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) ++{ ++ struct brcmf_info *drvr_priv = NULL; ++ struct net_device *ndev; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Allocate netdev, including space for private structure */ ++ ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup); ++ if (!ndev) { ++ brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); ++ goto fail; ++ } ++ ++ /* Allocate primary brcmf_info */ ++ drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); ++ if (!drvr_priv) ++ goto fail; ++ ++ /* ++ * Save the brcmf_info into the priv ++ */ ++ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); ++ ++ if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) == ++ BRCMF_BAD_IF) ++ goto fail; ++ ++ ndev->netdev_ops = NULL; ++ mutex_init(&drvr_priv->proto_block); ++ ++ /* Link to info module */ ++ drvr_priv->pub.info = drvr_priv; ++ ++ /* Link to bus module */ ++ drvr_priv->pub.bus = bus; ++ drvr_priv->pub.hdrlen = bus_hdrlen; ++ ++ /* Attach and link in the protocol */ ++ if (brcmf_proto_attach(&drvr_priv->pub) != 0) { ++ brcmf_dbg(ERROR, "brcmf_prot_attach failed\n"); ++ goto fail; ++ } ++ ++ /* Attach and link in the cfg80211 */ ++ drvr_priv->pub.config = ++ brcmf_cfg80211_attach(ndev, ++ brcmf_bus_get_device(bus), ++ &drvr_priv->pub); ++ if (drvr_priv->pub.config == NULL) { ++ brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); ++ goto fail; ++ } ++ ++ INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address); ++ INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); ++ ++ /* ++ * Save the brcmf_info into the priv ++ */ ++ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); ++ ++ return &drvr_priv->pub; ++ ++fail: ++ if (ndev) ++ free_netdev(ndev); ++ if (drvr_priv) ++ brcmf_detach(&drvr_priv->pub); ++ ++ return NULL; ++} ++ ++int brcmf_bus_start(struct brcmf_pub *drvr) ++{ ++ int ret = -1; ++ struct brcmf_info *drvr_priv = drvr->info; ++ /* Room for "event_msgs" + '\0' + bitvec */ ++ char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; ++ ++ brcmf_dbg(TRACE, "\n"); ++ ++ /* Bring up the bus */ ++ ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); ++ if (ret != 0) { ++ brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret); ++ return ret; ++ } ++ ++ /* If bus is not ready, can't come up */ ++ if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { ++ brcmf_dbg(ERROR, "failed bus is not ready\n"); ++ return -ENODEV; ++ } ++ ++ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf, ++ sizeof(iovbuf)); ++ memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); ++ ++ setbit(drvr->eventmask, BRCMF_E_SET_SSID); ++ setbit(drvr->eventmask, BRCMF_E_PRUNE); ++ setbit(drvr->eventmask, BRCMF_E_AUTH); ++ setbit(drvr->eventmask, BRCMF_E_REASSOC); ++ setbit(drvr->eventmask, BRCMF_E_REASSOC_IND); ++ setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND); ++ setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND); ++ setbit(drvr->eventmask, BRCMF_E_DISASSOC); ++ setbit(drvr->eventmask, BRCMF_E_JOIN); ++ setbit(drvr->eventmask, BRCMF_E_ASSOC_IND); ++ setbit(drvr->eventmask, BRCMF_E_PSK_SUP); ++ setbit(drvr->eventmask, BRCMF_E_LINK); ++ setbit(drvr->eventmask, BRCMF_E_NDIS_LINK); ++ setbit(drvr->eventmask, BRCMF_E_MIC_ERROR); ++ setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE); ++ setbit(drvr->eventmask, BRCMF_E_TXFAIL); ++ setbit(drvr->eventmask, BRCMF_E_JOIN_START); ++ setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE); ++ ++/* enable dongle roaming event */ ++ ++ drvr->pktfilter_count = 1; ++ /* Setup filter to allow only unicast */ ++ drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; ++ ++ /* Bus is ready, do any protocol initialization */ ++ ret = brcmf_proto_init(&drvr_priv->pub); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static struct net_device_ops brcmf_netdev_ops_pri = { ++ .ndo_open = brcmf_netdev_open, ++ .ndo_stop = brcmf_netdev_stop, ++ .ndo_get_stats = brcmf_netdev_get_stats, ++ .ndo_do_ioctl = brcmf_netdev_ioctl_entry, ++ .ndo_start_xmit = brcmf_netdev_start_xmit, ++ .ndo_set_mac_address = brcmf_netdev_set_mac_address, ++ .ndo_set_rx_mode = brcmf_netdev_set_multicast_list ++}; ++ ++int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ struct net_device *ndev; ++ u8 temp_addr[ETH_ALEN] = { ++ 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; ++ ++ brcmf_dbg(TRACE, "ifidx %d\n", ifidx); ++ ++ ndev = drvr_priv->iflist[ifidx]->ndev; ++ ndev->netdev_ops = &brcmf_netdev_ops_pri; ++ ++ /* ++ * We have to use the primary MAC for virtual interfaces ++ */ ++ if (ifidx != 0) { ++ /* for virtual interfaces use the primary MAC */ ++ memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN); ++ ++ } ++ ++ if (ifidx == 1) { ++ brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); ++ /* ACCESSPOINT INTERFACE CASE */ ++ temp_addr[0] |= 0X02; /* set bit 2 , ++ - Locally Administered address */ ++ ++ } ++ ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen; ++ ndev->ethtool_ops = &brcmf_ethtool_ops; ++ ++ drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len + ++ drvr_priv->pub.hdrlen; ++ ++ memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); ++ ++ if (register_netdev(ndev) != 0) { ++ brcmf_dbg(ERROR, "couldn't register the net device\n"); ++ goto fail; ++ } ++ ++ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); ++ ++ return 0; ++ ++fail: ++ ndev->netdev_ops = NULL; ++ return -EBADE; ++} ++ ++static void brcmf_bus_detach(struct brcmf_pub *drvr) ++{ ++ struct brcmf_info *drvr_priv; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (drvr) { ++ drvr_priv = drvr->info; ++ if (drvr_priv) { ++ /* Stop the protocol module */ ++ brcmf_proto_stop(&drvr_priv->pub); ++ ++ /* Stop the bus module */ ++ brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); ++ } ++ } ++} ++ ++void brcmf_detach(struct brcmf_pub *drvr) ++{ ++ struct brcmf_info *drvr_priv; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (drvr) { ++ drvr_priv = drvr->info; ++ if (drvr_priv) { ++ struct brcmf_if *ifp; ++ int i; ++ ++ for (i = 1; i < BRCMF_MAX_IFS; i++) ++ if (drvr_priv->iflist[i]) ++ brcmf_del_if(drvr_priv, i); ++ ++ ifp = drvr_priv->iflist[0]; ++ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { ++ rtnl_lock(); ++ brcmf_netdev_stop(ifp->ndev); ++ rtnl_unlock(); ++ unregister_netdev(ifp->ndev); ++ } ++ ++ cancel_work_sync(&drvr_priv->setmacaddr_work); ++ cancel_work_sync(&drvr_priv->multicast_work); ++ ++ brcmf_bus_detach(drvr); ++ ++ if (drvr->prot) ++ brcmf_proto_detach(drvr); ++ ++ brcmf_cfg80211_detach(drvr->config); ++ ++ free_netdev(ifp->ndev); ++ kfree(ifp); ++ kfree(drvr_priv); ++ } ++ } ++} ++ ++static void __exit brcmf_module_cleanup(void) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ brcmf_bus_unregister(); ++} ++ ++static int __init brcmf_module_init(void) ++{ ++ int error; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ error = brcmf_bus_register(); ++ ++ if (error) { ++ brcmf_dbg(ERROR, "brcmf_bus_register failed\n"); ++ goto failed; ++ } ++ return 0; ++ ++failed: ++ return -EINVAL; ++} ++ ++module_init(brcmf_module_init); ++module_exit(brcmf_module_cleanup); ++ ++int brcmf_os_proto_block(struct brcmf_pub *drvr) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ ++ if (drvr_priv) { ++ mutex_lock(&drvr_priv->proto_block); ++ return 1; ++ } ++ return 0; ++} ++ ++int brcmf_os_proto_unblock(struct brcmf_pub *drvr) ++{ ++ struct brcmf_info *drvr_priv = drvr->info; ++ ++ if (drvr_priv) { ++ mutex_unlock(&drvr_priv->proto_block); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv) ++{ ++ return atomic_read(&drvr_priv->pend_8021x_cnt); ++} ++ ++#define MAX_WAIT_FOR_8021X_TX 10 ++ ++int brcmf_netdev_wait_pend8021x(struct net_device *ndev) ++{ ++ struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev); ++ int timeout = 10 * HZ / 1000; ++ int ntimes = MAX_WAIT_FOR_8021X_TX; ++ int pend = brcmf_get_pend_8021x_cnt(drvr_priv); ++ ++ while (ntimes && pend) { ++ if (pend) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(timeout); ++ set_current_state(TASK_RUNNING); ++ ntimes--; ++ } ++ pend = brcmf_get_pend_8021x_cnt(drvr_priv); ++ } ++ return pend; ++} ++ ++#ifdef BCMDBG ++int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size) ++{ ++ int ret = 0; ++ struct file *fp; ++ mm_segment_t old_fs; ++ loff_t pos = 0; ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* open file to write */ ++ fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640); ++ if (!fp) { ++ brcmf_dbg(ERROR, "open file error\n"); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Write buf to file */ ++ fp->f_op->write(fp, (char __user *)buf, size, &pos); ++ ++exit: ++ /* free buf before return */ ++ kfree(buf); ++ /* close file before return */ ++ if (fp) ++ filp_close(fp, current->files); ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ return ret; ++} ++#endif /* BCMDBG */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h.orig 2011-11-09 13:46:58.232800795 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h 2011-11-09 13:47:16.983566378 -0500 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCMF_PROTO_H_ ++#define _BRCMF_PROTO_H_ ++ ++/* ++ * Exported from the brcmf protocol module (brcmf_cdc) ++ */ ++ ++/* Linkage, sets prot link and updates hdrlen in pub */ ++extern int brcmf_proto_attach(struct brcmf_pub *drvr); ++ ++/* Unlink, frees allocated protocol memory (including brcmf_proto) */ ++extern void brcmf_proto_detach(struct brcmf_pub *drvr); ++ ++/* Initialize protocol: sync w/dongle state. ++ * Sets dongle media info (iswl, drv_version, mac address). ++ */ ++extern int brcmf_proto_init(struct brcmf_pub *drvr); ++ ++/* Stop protocol: sync w/dongle state. */ ++extern void brcmf_proto_stop(struct brcmf_pub *drvr); ++ ++/* Add any protocol-specific data header. ++ * Caller must reserve prot_hdrlen prepend space. ++ */ ++extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, ++ struct sk_buff *txp); ++ ++/* Remove any protocol-specific data header. */ ++extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx, ++ struct sk_buff *rxp); ++ ++/* Use protocol to issue command to dongle */ ++extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, ++ struct brcmf_dcmd *dcmd, int len); ++ ++/* Update local copy of dongle statistics */ ++extern void brcmf_proto_dstats(struct brcmf_pub *drvr); ++ ++extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr); ++ ++extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, ++ uint cmd, void *buf, uint len); ++ ++#endif /* _BRCMF_PROTO_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c.orig 2011-11-09 13:46:58.235800758 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c 2011-11-09 13:47:16.986566342 -0500 +@@ -0,0 +1,4591 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sdio_host.h" ++ ++#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ ++ ++#ifdef BCMDBG ++ ++#define BRCMF_TRAP_INFO_SIZE 80 ++ ++#define CBUF_LEN (128) ++ ++struct rte_log_le { ++ __le32 buf; /* Can't be pointer on (64-bit) hosts */ ++ __le32 buf_size; ++ __le32 idx; ++ char *_buf_compat; /* Redundant pointer for backward compat. */ ++}; ++ ++struct rte_console { ++ /* Virtual UART ++ * When there is no UART (e.g. Quickturn), ++ * the host should write a complete ++ * input line directly into cbuf and then write ++ * the length into vcons_in. ++ * This may also be used when there is a real UART ++ * (at risk of conflicting with ++ * the real UART). vcons_out is currently unused. ++ */ ++ uint vcons_in; ++ uint vcons_out; ++ ++ /* Output (logging) buffer ++ * Console output is written to a ring buffer log_buf at index log_idx. ++ * The host may read the output when it sees log_idx advance. ++ * Output will be lost if the output wraps around faster than the host ++ * polls. ++ */ ++ struct rte_log_le log_le; ++ ++ /* Console input line buffer ++ * Characters are read one at a time into cbuf ++ * until is received, then ++ * the buffer is processed as a command line. ++ * Also used for virtual UART. ++ */ ++ uint cbuf_idx; ++ char cbuf[CBUF_LEN]; ++}; ++ ++#endif /* BCMDBG */ ++#include ++ ++#include "dhd.h" ++#include "dhd_bus.h" ++#include "dhd_proto.h" ++#include "dhd_dbg.h" ++#include ++ ++#define TXQLEN 2048 /* bulk tx queue length */ ++#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ ++#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */ ++#define PRIOMASK 7 ++ ++#define TXRETRIES 2 /* # of retries for tx frames */ ++ ++#define BRCMF_RXBOUND 50 /* Default for max rx frames in ++ one scheduling */ ++ ++#define BRCMF_TXBOUND 20 /* Default for max tx frames in ++ one scheduling */ ++ ++#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ ++ ++#define MEMBLOCK 2048 /* Block size used for downloading ++ of dongle image */ ++#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold ++ biggest possible glom */ ++ ++#define BRCMF_FIRSTREAD (1 << 6) ++ ++ ++/* SBSDIO_DEVICE_CTL */ ++ ++/* 1: device will assert busy signal when receiving CMD53 */ ++#define SBSDIO_DEVCTL_SETBUSY 0x01 ++/* 1: assertion of sdio interrupt is synchronous to the sdio clock */ ++#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 ++/* 1: mask all interrupts to host except the chipActive (rev 8) */ ++#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 ++/* 1: isolate internal sdio signals, put external pads in tri-state; requires ++ * sdio bus power cycle to clear (rev 9) */ ++#define SBSDIO_DEVCTL_PADS_ISO 0x08 ++/* Force SD->SB reset mapping (rev 11) */ ++#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 ++/* Determined by CoreControl bit */ ++#define SBSDIO_DEVCTL_RST_CORECTL 0x00 ++/* Force backplane reset */ ++#define SBSDIO_DEVCTL_RST_BPRESET 0x10 ++/* Force no backplane reset */ ++#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 ++ ++/* SBSDIO_FUNC1_CHIPCLKCSR */ ++ ++/* Force ALP request to backplane */ ++#define SBSDIO_FORCE_ALP 0x01 ++/* Force HT request to backplane */ ++#define SBSDIO_FORCE_HT 0x02 ++/* Force ILP request to backplane */ ++#define SBSDIO_FORCE_ILP 0x04 ++/* Make ALP ready (power up xtal) */ ++#define SBSDIO_ALP_AVAIL_REQ 0x08 ++/* Make HT ready (power up PLL) */ ++#define SBSDIO_HT_AVAIL_REQ 0x10 ++/* Squelch clock requests from HW */ ++#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 ++/* Status: ALP is ready */ ++#define SBSDIO_ALP_AVAIL 0x40 ++/* Status: HT is ready */ ++#define SBSDIO_HT_AVAIL 0x80 ++ ++#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) ++#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) ++#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) ++#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) ++ ++#define SBSDIO_CLKAV(regval, alponly) \ ++ (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) ++ ++/* direct(mapped) cis space */ ++ ++/* MAPPED common CIS address */ ++#define SBSDIO_CIS_BASE_COMMON 0x1000 ++/* maximum bytes in one CIS */ ++#define SBSDIO_CIS_SIZE_LIMIT 0x200 ++/* cis offset addr is < 17 bits */ ++#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF ++ ++/* manfid tuple length, include tuple, link bytes */ ++#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 ++ ++/* intstatus */ ++#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ ++#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ ++#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ ++#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ ++#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ ++#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ ++#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ ++#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ ++#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ ++#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ ++#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ ++#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ ++#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ ++#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ ++#define I_PC (1 << 10) /* descriptor error */ ++#define I_PD (1 << 11) /* data error */ ++#define I_DE (1 << 12) /* Descriptor protocol Error */ ++#define I_RU (1 << 13) /* Receive descriptor Underflow */ ++#define I_RO (1 << 14) /* Receive fifo Overflow */ ++#define I_XU (1 << 15) /* Transmit fifo Underflow */ ++#define I_RI (1 << 16) /* Receive Interrupt */ ++#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ ++#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ ++#define I_XI (1 << 24) /* Transmit Interrupt */ ++#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ ++#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ ++#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ ++#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ ++#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */ ++#define I_SRESET (1 << 30) /* CCCR RES interrupt */ ++#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ ++#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) ++#define I_DMA (I_RI | I_XI | I_ERRORS) ++ ++/* corecontrol */ ++#define CC_CISRDY (1 << 0) /* CIS Ready */ ++#define CC_BPRESEN (1 << 1) /* CCCR RES signal */ ++#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ ++#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */ ++#define CC_XMTDATAAVAIL_MODE (1 << 4) ++#define CC_XMTDATAAVAIL_CTRL (1 << 5) ++ ++/* SDA_FRAMECTRL */ ++#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */ ++#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */ ++ ++/* HW frame tag */ ++#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */ ++ ++/* Total length of frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) ++ ++/* ++ * Software allocation of To SB Mailbox resources ++ */ ++ ++/* tosbmailbox bits corresponding to intstatus bits */ ++#define SMB_NAK (1 << 0) /* Frame NAK */ ++#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */ ++#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */ ++#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */ ++ ++/* tosbmailboxdata */ ++#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */ ++ ++/* ++ * Software allocation of To Host Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */ ++#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */ ++#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */ ++#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */ ++ ++/* tohostmailboxdata */ ++#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */ ++#define HMB_DATA_DEVREADY 2 /* talk to host after enable */ ++#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */ ++#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */ ++ ++#define HMB_DATA_FCDATA_MASK 0xff000000 ++#define HMB_DATA_FCDATA_SHIFT 24 ++ ++#define HMB_DATA_VERSION_MASK 0x00ff0000 ++#define HMB_DATA_VERSION_SHIFT 16 ++ ++/* ++ * Software-defined protocol header ++ */ ++ ++/* Current protocol version */ ++#define SDPCM_PROT_VERSION 4 ++ ++/* SW frame header */ ++#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff) ++ ++#define SDPCM_CHANNEL_MASK 0x00000f00 ++#define SDPCM_CHANNEL_SHIFT 8 ++#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f) ++ ++#define SDPCM_NEXTLEN_OFFSET 2 ++ ++/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ ++#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ ++#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) ++#define SDPCM_DOFFSET_MASK 0xff000000 ++#define SDPCM_DOFFSET_SHIFT 24 ++#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ ++#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff) ++#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ ++#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) ++ ++#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ ++ ++/* logical channel numbers */ ++#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */ ++#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ ++#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ ++#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */ ++#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ ++ ++#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */ ++ ++#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) ++ ++/* ++ * Shared structure between dongle and the host. ++ * The structure contains pointers to trap or assert information. ++ */ ++#define SDPCM_SHARED_VERSION 0x0002 ++#define SDPCM_SHARED_VERSION_MASK 0x00FF ++#define SDPCM_SHARED_ASSERT_BUILT 0x0100 ++#define SDPCM_SHARED_ASSERT 0x0200 ++#define SDPCM_SHARED_TRAP 0x0400 ++ ++/* Space for header read, limit for data packets */ ++#define MAX_HDR_READ (1 << 6) ++#define MAX_RX_DATASZ 2048 ++ ++/* Maximum milliseconds to wait for F2 to come up */ ++#define BRCMF_WAIT_F2RDY 3000 ++ ++/* Bump up limit on waiting for HT to account for first startup; ++ * if the image is doing a CRC calculation before programming the PMU ++ * for HT availability, it could take a couple hundred ms more, so ++ * max out at a 1 second (1000000us). ++ */ ++#undef PMU_MAX_TRANSITION_DLY ++#define PMU_MAX_TRANSITION_DLY 1000000 ++ ++/* Value for ChipClockCSR during initial setup */ ++#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \ ++ SBSDIO_ALP_AVAIL_REQ) ++ ++/* Flags for SDH calls */ ++#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) ++ ++/* sbimstate */ ++#define SBIM_IBE 0x20000 /* inbanderror */ ++#define SBIM_TO 0x40000 /* timeout */ ++#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ ++#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ ++ ++/* sbtmstatelow */ ++ ++/* reset */ ++#define SBTML_RESET 0x0001 ++/* reject field */ ++#define SBTML_REJ_MASK 0x0006 ++/* reject */ ++#define SBTML_REJ 0x0002 ++/* temporary reject, for error recovery */ ++#define SBTML_TMPREJ 0x0004 ++ ++/* Shift to locate the SI control flags in sbtml */ ++#define SBTML_SICF_SHIFT 16 ++ ++/* sbtmstatehigh */ ++#define SBTMH_SERR 0x0001 /* serror */ ++#define SBTMH_INT 0x0002 /* interrupt */ ++#define SBTMH_BUSY 0x0004 /* busy */ ++#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ ++ ++/* Shift to locate the SI status flags in sbtmh */ ++#define SBTMH_SISF_SHIFT 16 ++ ++/* sbidlow */ ++#define SBIDL_INIT 0x80 /* initiator */ ++ ++/* sbidhigh */ ++#define SBIDH_RC_MASK 0x000f /* revision code */ ++#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ ++#define SBIDH_RCE_SHIFT 8 ++#define SBCOREREV(sbidh) \ ++ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \ ++ ((sbidh) & SBIDH_RC_MASK)) ++#define SBIDH_CC_MASK 0x8ff0 /* core code */ ++#define SBIDH_CC_SHIFT 4 ++#define SBIDH_VC_MASK 0xffff0000 /* vendor code */ ++#define SBIDH_VC_SHIFT 16 ++ ++/* ++ * Conversion of 802.1D priority to precedence level ++ */ ++static uint prio2prec(u32 prio) ++{ ++ return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? ++ (prio^2) : prio; ++} ++ ++/* ++ * Core reg address translation. ++ * Both macro's returns a 32 bits byte address on the backplane bus. ++ */ ++#define CORE_CC_REG(base, field) \ ++ (base + offsetof(struct chipcregs, field)) ++#define CORE_BUS_REG(base, field) \ ++ (base + offsetof(struct sdpcmd_regs, field)) ++#define CORE_SB(base, field) \ ++ (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) ++ ++/* core registers */ ++struct sdpcmd_regs { ++ u32 corecontrol; /* 0x00, rev8 */ ++ u32 corestatus; /* rev8 */ ++ u32 PAD[1]; ++ u32 biststatus; /* rev8 */ ++ ++ /* PCMCIA access */ ++ u16 pcmciamesportaladdr; /* 0x010, rev8 */ ++ u16 PAD[1]; ++ u16 pcmciamesportalmask; /* rev8 */ ++ u16 PAD[1]; ++ u16 pcmciawrframebc; /* rev8 */ ++ u16 PAD[1]; ++ u16 pcmciaunderflowtimer; /* rev8 */ ++ u16 PAD[1]; ++ ++ /* interrupt */ ++ u32 intstatus; /* 0x020, rev8 */ ++ u32 hostintmask; /* rev8 */ ++ u32 intmask; /* rev8 */ ++ u32 sbintstatus; /* rev8 */ ++ u32 sbintmask; /* rev8 */ ++ u32 funcintmask; /* rev4 */ ++ u32 PAD[2]; ++ u32 tosbmailbox; /* 0x040, rev8 */ ++ u32 tohostmailbox; /* rev8 */ ++ u32 tosbmailboxdata; /* rev8 */ ++ u32 tohostmailboxdata; /* rev8 */ ++ ++ /* synchronized access to registers in SDIO clock domain */ ++ u32 sdioaccess; /* 0x050, rev8 */ ++ u32 PAD[3]; ++ ++ /* PCMCIA frame control */ ++ u8 pcmciaframectrl; /* 0x060, rev8 */ ++ u8 PAD[3]; ++ u8 pcmciawatermark; /* rev8 */ ++ u8 PAD[155]; ++ ++ /* interrupt batching control */ ++ u32 intrcvlazy; /* 0x100, rev8 */ ++ u32 PAD[3]; ++ ++ /* counters */ ++ u32 cmd52rd; /* 0x110, rev8 */ ++ u32 cmd52wr; /* rev8 */ ++ u32 cmd53rd; /* rev8 */ ++ u32 cmd53wr; /* rev8 */ ++ u32 abort; /* rev8 */ ++ u32 datacrcerror; /* rev8 */ ++ u32 rdoutofsync; /* rev8 */ ++ u32 wroutofsync; /* rev8 */ ++ u32 writebusy; /* rev8 */ ++ u32 readwait; /* rev8 */ ++ u32 readterm; /* rev8 */ ++ u32 writeterm; /* rev8 */ ++ u32 PAD[40]; ++ u32 clockctlstatus; /* rev8 */ ++ u32 PAD[7]; ++ ++ u32 PAD[128]; /* DMA engines */ ++ ++ /* SDIO/PCMCIA CIS region */ ++ char cis[512]; /* 0x400-0x5ff, rev6 */ ++ ++ /* PCMCIA function control registers */ ++ char pcmciafcr[256]; /* 0x600-6ff, rev6 */ ++ u16 PAD[55]; ++ ++ /* PCMCIA backplane access */ ++ u16 backplanecsr; /* 0x76E, rev6 */ ++ u16 backplaneaddr0; /* rev6 */ ++ u16 backplaneaddr1; /* rev6 */ ++ u16 backplaneaddr2; /* rev6 */ ++ u16 backplaneaddr3; /* rev6 */ ++ u16 backplanedata0; /* rev6 */ ++ u16 backplanedata1; /* rev6 */ ++ u16 backplanedata2; /* rev6 */ ++ u16 backplanedata3; /* rev6 */ ++ u16 PAD[31]; ++ ++ /* sprom "size" & "blank" info */ ++ u16 spromstatus; /* 0x7BE, rev2 */ ++ u32 PAD[464]; ++ ++ u16 PAD[0x80]; ++}; ++ ++#ifdef BCMDBG ++/* Device console log buffer state */ ++struct brcmf_console { ++ uint count; /* Poll interval msec counter */ ++ uint log_addr; /* Log struct address (fixed) */ ++ struct rte_log_le log_le; /* Log struct (host copy) */ ++ uint bufsize; /* Size of log buffer */ ++ u8 *buf; /* Log buffer (host copy) */ ++ uint last; /* Last buffer read index */ ++}; ++#endif /* BCMDBG */ ++ ++struct sdpcm_shared { ++ u32 flags; ++ u32 trap_addr; ++ u32 assert_exp_addr; ++ u32 assert_file_addr; ++ u32 assert_line; ++ u32 console_addr; /* Address of struct rte_console */ ++ u32 msgtrace_addr; ++ u8 tag[32]; ++}; ++ ++struct sdpcm_shared_le { ++ __le32 flags; ++ __le32 trap_addr; ++ __le32 assert_exp_addr; ++ __le32 assert_file_addr; ++ __le32 assert_line; ++ __le32 console_addr; /* Address of struct rte_console */ ++ __le32 msgtrace_addr; ++ u8 tag[32]; ++}; ++ ++ ++/* misc chip info needed by some of the routines */ ++struct chip_info { ++ u32 chip; ++ u32 chiprev; ++ u32 cccorebase; ++ u32 ccrev; ++ u32 cccaps; ++ u32 buscorebase; /* 32 bits backplane bus address */ ++ u32 buscorerev; ++ u32 buscoretype; ++ u32 ramcorebase; ++ u32 armcorebase; ++ u32 pmurev; ++ u32 ramsize; ++}; ++ ++/* Private data for SDIO bus interaction */ ++struct brcmf_bus { ++ struct brcmf_pub *drvr; ++ ++ struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ ++ struct chip_info *ci; /* Chip info struct */ ++ char *vars; /* Variables (from CIS and/or other) */ ++ uint varsz; /* Size of variables buffer */ ++ ++ u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ ++ u32 hostintmask; /* Copy of Host Interrupt Mask */ ++ u32 intstatus; /* Intstatus bits (events) pending */ ++ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ ++ bool fcstate; /* State of dongle flow-control */ ++ ++ uint blocksize; /* Block size of SDIO transfers */ ++ uint roundup; /* Max roundup limit */ ++ ++ struct pktq txq; /* Queue length used for flow-control */ ++ u8 flowcontrol; /* per prio flow control bitmask */ ++ u8 tx_seq; /* Transmit sequence number (next) */ ++ u8 tx_max; /* Maximum transmit sequence allowed */ ++ ++ u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; ++ u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ ++ u16 nextlen; /* Next Read Len from last header */ ++ u8 rx_seq; /* Receive sequence number (expected) */ ++ bool rxskip; /* Skip receive (awaiting NAK ACK) */ ++ ++ uint rxbound; /* Rx frames to read before resched */ ++ uint txbound; /* Tx frames to send before resched */ ++ uint txminmax; ++ ++ struct sk_buff *glomd; /* Packet containing glomming descriptor */ ++ struct sk_buff *glom; /* Packet chain for glommed superframe */ ++ uint glomerr; /* Glom packet read errors */ ++ ++ u8 *rxbuf; /* Buffer for receiving control packets */ ++ uint rxblen; /* Allocated length of rxbuf */ ++ u8 *rxctl; /* Aligned pointer into rxbuf */ ++ u8 *databuf; /* Buffer for receiving big glom packet */ ++ u8 *dataptr; /* Aligned pointer into databuf */ ++ uint rxlen; /* Length of valid data in buffer */ ++ ++ u8 sdpcm_ver; /* Bus protocol reported by dongle */ ++ ++ bool intr; /* Use interrupts */ ++ bool poll; /* Use polling */ ++ bool ipend; /* Device interrupt is pending */ ++ uint intrcount; /* Count of device interrupt callbacks */ ++ uint lastintrs; /* Count as of last watchdog timer */ ++ uint spurious; /* Count of spurious interrupts */ ++ uint pollrate; /* Ticks between device polls */ ++ uint polltick; /* Tick counter */ ++ uint pollcnt; /* Count of active polls */ ++ ++#ifdef BCMDBG ++ uint console_interval; ++ struct brcmf_console console; /* Console output polling support */ ++ uint console_addr; /* Console address from shared struct */ ++#endif /* BCMDBG */ ++ ++ uint regfails; /* Count of R_REG failures */ ++ ++ uint clkstate; /* State of sd and backplane clock(s) */ ++ bool activity; /* Activity flag for clock down */ ++ s32 idletime; /* Control for activity timeout */ ++ s32 idlecount; /* Activity timeout counter */ ++ s32 idleclock; /* How to set bus driver when idle */ ++ s32 sd_rxchain; ++ bool use_rxchain; /* If brcmf should use PKT chains */ ++ bool sleeping; /* Is SDIO bus sleeping? */ ++ bool rxflow_mode; /* Rx flow control mode */ ++ bool rxflow; /* Is rx flow control on */ ++ bool alp_only; /* Don't use HT clock (ALP only) */ ++/* Field to decide if rx of control frames happen in rxbuf or lb-pool */ ++ bool usebufpool; ++ ++ /* Some additional counters */ ++ uint tx_sderrs; /* Count of tx attempts with sd errors */ ++ uint fcqueued; /* Tx packets that got queued */ ++ uint rxrtx; /* Count of rtx requests (NAK to dongle) */ ++ uint rx_toolong; /* Receive frames too long to receive */ ++ uint rxc_errors; /* SDIO errors when reading control frames */ ++ uint rx_hdrfail; /* SDIO errors on header reads */ ++ uint rx_badhdr; /* Bad received headers (roosync?) */ ++ uint rx_badseq; /* Mismatched rx sequence number */ ++ uint fc_rcvd; /* Number of flow-control events received */ ++ uint fc_xoff; /* Number which turned on flow-control */ ++ uint fc_xon; /* Number which turned off flow-control */ ++ uint rxglomfail; /* Failed deglom attempts */ ++ uint rxglomframes; /* Number of glom frames (superframes) */ ++ uint rxglompkts; /* Number of packets from glom frames */ ++ uint f2rxhdrs; /* Number of header reads */ ++ uint f2rxdata; /* Number of frame data reads */ ++ uint f2txdata; /* Number of f2 frame writes */ ++ uint f1regdata; /* Number of f1 register accesses */ ++ ++ u8 *ctrl_frame_buf; ++ u32 ctrl_frame_len; ++ bool ctrl_frame_stat; ++ ++ spinlock_t txqlock; ++ wait_queue_head_t ctrl_wait; ++ wait_queue_head_t dcmd_resp_wait; ++ ++ struct timer_list timer; ++ struct completion watchdog_wait; ++ struct task_struct *watchdog_tsk; ++ bool wd_timer_valid; ++ uint save_ms; ++ ++ struct task_struct *dpc_tsk; ++ struct completion dpc_wait; ++ ++ struct semaphore sdsem; ++ ++ const char *fw_name; ++ const struct firmware *firmware; ++ const char *nv_name; ++ u32 fw_ptr; ++}; ++ ++struct sbconfig { ++ u32 PAD[2]; ++ u32 sbipsflag; /* initiator port ocp slave flag */ ++ u32 PAD[3]; ++ u32 sbtpsflag; /* target port ocp slave flag */ ++ u32 PAD[11]; ++ u32 sbtmerrloga; /* (sonics >= 2.3) */ ++ u32 PAD; ++ u32 sbtmerrlog; /* (sonics >= 2.3) */ ++ u32 PAD[3]; ++ u32 sbadmatch3; /* address match3 */ ++ u32 PAD; ++ u32 sbadmatch2; /* address match2 */ ++ u32 PAD; ++ u32 sbadmatch1; /* address match1 */ ++ u32 PAD[7]; ++ u32 sbimstate; /* initiator agent state */ ++ u32 sbintvec; /* interrupt mask */ ++ u32 sbtmstatelow; /* target state */ ++ u32 sbtmstatehigh; /* target state */ ++ u32 sbbwa0; /* bandwidth allocation table0 */ ++ u32 PAD; ++ u32 sbimconfiglow; /* initiator configuration */ ++ u32 sbimconfighigh; /* initiator configuration */ ++ u32 sbadmatch0; /* address match0 */ ++ u32 PAD; ++ u32 sbtmconfiglow; /* target configuration */ ++ u32 sbtmconfighigh; /* target configuration */ ++ u32 sbbconfig; /* broadcast configuration */ ++ u32 PAD; ++ u32 sbbstate; /* broadcast state */ ++ u32 PAD[3]; ++ u32 sbactcnfg; /* activate configuration */ ++ u32 PAD[3]; ++ u32 sbflagst; /* current sbflags */ ++ u32 PAD[3]; ++ u32 sbidlow; /* identification */ ++ u32 sbidhigh; /* identification */ ++}; ++ ++/* clkstate */ ++#define CLK_NONE 0 ++#define CLK_SDONLY 1 ++#define CLK_PENDING 2 /* Not used yet */ ++#define CLK_AVAIL 3 ++ ++#ifdef BCMDBG ++static int qcount[NUMPRIO]; ++static int tx_packets[NUMPRIO]; ++#endif /* BCMDBG */ ++ ++#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */ ++ ++#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL) ++ ++/* Retry count for register access failures */ ++static const uint retry_limit = 2; ++ ++/* Limit on rounding up frames */ ++static const uint max_roundup = 512; ++ ++#define ALIGNMENT 4 ++ ++static void pkt_align(struct sk_buff *p, int len, int align) ++{ ++ uint datalign; ++ datalign = (unsigned long)(p->data); ++ datalign = roundup(datalign, (align)) - datalign; ++ if (datalign) ++ skb_pull(p, datalign); ++ __skb_trim(p, len); ++} ++ ++/* To check if there's window offered */ ++static bool data_ok(struct brcmf_bus *bus) ++{ ++ return (u8)(bus->tx_max - bus->tx_seq) != 0 && ++ ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; ++} ++ ++/* ++ * Reads a register in the SDIO hardware block. This block occupies a series of ++ * adresses on the 32 bit backplane bus. ++ */ ++static void ++r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) ++{ ++ *retryvar = 0; ++ do { ++ *regvar = brcmf_sdcard_reg_read(bus->sdiodev, ++ bus->ci->buscorebase + reg_offset, sizeof(u32)); ++ } while (brcmf_sdcard_regfail(bus->sdiodev) && ++ (++(*retryvar) <= retry_limit)); ++ if (*retryvar) { ++ bus->regfails += (*retryvar-1); ++ if (*retryvar > retry_limit) { ++ brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset); ++ *regvar = 0; ++ } ++ } ++} ++ ++static void ++w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) ++{ ++ *retryvar = 0; ++ do { ++ brcmf_sdcard_reg_write(bus->sdiodev, ++ bus->ci->buscorebase + reg_offset, ++ sizeof(u32), regval); ++ } while (brcmf_sdcard_regfail(bus->sdiodev) && ++ (++(*retryvar) <= retry_limit)); ++ if (*retryvar) { ++ bus->regfails += (*retryvar-1); ++ if (*retryvar > retry_limit) ++ brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n", ++ reg_offset); ++ } ++} ++ ++#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) ++ ++#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) ++ ++/* Packet free applicable unconditionally for sdio and sdspi. ++ * Conditional if bufpool was present for gspi bus. ++ */ ++static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) ++{ ++ if (bus->usebufpool) ++ brcmu_pkt_buf_free_skb(pkt); ++} ++ ++/* Turn backplane clock on or off */ ++static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) ++{ ++ int err; ++ u8 clkctl, clkreq, devctl; ++ unsigned long timeout; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ clkctl = 0; ++ ++ if (on) { ++ /* Request HT Avail */ ++ clkreq = ++ bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; ++ ++ if ((bus->ci->chip == BCM4329_CHIP_ID) ++ && (bus->ci->chiprev == 0)) ++ clkreq |= SBSDIO_FORCE_ALP; ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); ++ return -EBADE; ++ } ++ ++ if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID) ++ && (bus->ci->buscorerev == 9))) { ++ u32 dummy, retries; ++ r_sdreg32(bus, &dummy, ++ offsetof(struct sdpcmd_regs, clockctlstatus), ++ &retries); ++ } ++ ++ /* Check current status */ ++ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); ++ return -EBADE; ++ } ++ ++ /* Go to pending and await interrupt if appropriate */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { ++ /* Allow only clock-available interrupt */ ++ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", ++ err); ++ return -EBADE; ++ } ++ ++ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, devctl, &err); ++ brcmf_dbg(INFO, "CLKCTL: set PENDING\n"); ++ bus->clkstate = CLK_PENDING; ++ ++ return 0; ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = ++ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ /* Otherwise, wait here (polling) for HT Avail */ ++ timeout = jiffies + ++ msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000); ++ while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ &err); ++ if (time_after(jiffies, timeout)) ++ break; ++ else ++ usleep_range(5000, 10000); ++ } ++ if (err) { ++ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); ++ return -EBADE; ++ } ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n", ++ PMU_MAX_TRANSITION_DLY, clkctl); ++ return -EBADE; ++ } ++ ++ /* Mark clock available */ ++ bus->clkstate = CLK_AVAIL; ++ brcmf_dbg(INFO, "CLKCTL: turned ON\n"); ++ ++#if defined(BCMDBG) ++ if (bus->alp_only != true) { ++ if (SBSDIO_ALPONLY(clkctl)) ++ brcmf_dbg(ERROR, "HT Clock should be on\n"); ++ } ++#endif /* defined (BCMDBG) */ ++ ++ bus->activity = true; ++ } else { ++ clkreq = 0; ++ ++ if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ bus->clkstate = CLK_SDONLY; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ brcmf_dbg(INFO, "CLKCTL: turned OFF\n"); ++ if (err) { ++ brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", ++ err); ++ return -EBADE; ++ } ++ } ++ return 0; ++} ++ ++/* Change idle/active SD state */ ++static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (on) ++ bus->clkstate = CLK_SDONLY; ++ else ++ bus->clkstate = CLK_NONE; ++ ++ return 0; ++} ++ ++/* Transition SD and backplane clock readiness */ ++static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) ++{ ++#ifdef BCMDBG ++ uint oldstate = bus->clkstate; ++#endif /* BCMDBG */ ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Early exit if we're already there */ ++ if (bus->clkstate == target) { ++ if (target == CLK_AVAIL) { ++ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); ++ bus->activity = true; ++ } ++ return 0; ++ } ++ ++ switch (target) { ++ case CLK_AVAIL: ++ /* Make sure SD clock is available */ ++ if (bus->clkstate == CLK_NONE) ++ brcmf_sdbrcm_sdclk(bus, true); ++ /* Now request HT Avail on the backplane */ ++ brcmf_sdbrcm_htclk(bus, true, pendok); ++ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); ++ bus->activity = true; ++ break; ++ ++ case CLK_SDONLY: ++ /* Remove HT request, or bring up SD clock */ ++ if (bus->clkstate == CLK_NONE) ++ brcmf_sdbrcm_sdclk(bus, true); ++ else if (bus->clkstate == CLK_AVAIL) ++ brcmf_sdbrcm_htclk(bus, false, false); ++ else ++ brcmf_dbg(ERROR, "request for %d -> %d\n", ++ bus->clkstate, target); ++ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); ++ break; ++ ++ case CLK_NONE: ++ /* Make sure to remove HT request */ ++ if (bus->clkstate == CLK_AVAIL) ++ brcmf_sdbrcm_htclk(bus, false, false); ++ /* Now remove the SD clock */ ++ brcmf_sdbrcm_sdclk(bus, false); ++ brcmf_sdbrcm_wd_timer(bus, 0); ++ break; ++ } ++#ifdef BCMDBG ++ brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate); ++#endif /* BCMDBG */ ++ ++ return 0; ++} ++ ++static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) ++{ ++ uint retries = 0; ++ ++ brcmf_dbg(INFO, "request %s (currently %s)\n", ++ sleep ? "SLEEP" : "WAKE", ++ bus->sleeping ? "SLEEP" : "WAKE"); ++ ++ /* Done if we're already in the requested state */ ++ if (sleep == bus->sleeping) ++ return 0; ++ ++ /* Going to sleep: set the alarm and turn off the lights... */ ++ if (sleep) { ++ /* Don't sleep if something is pending */ ++ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) ++ return -EBUSY; ++ ++ /* Make sure the controller has the bus up */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ ++ /* Tell device to start using OOB wakeup */ ++ w_sdreg32(bus, SMB_USE_OOB, ++ offsetof(struct sdpcmd_regs, tosbmailbox), &retries); ++ if (retries > retry_limit) ++ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); ++ ++ /* Turn off our contribution to the HT clock request */ ++ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); ++ ++ /* Isolate the bus */ ++ if (bus->ci->chip != BCM4329_CHIP_ID) { ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_PADS_ISO, NULL); ++ } ++ ++ /* Change state */ ++ bus->sleeping = true; ++ ++ } else { ++ /* Waking up: bus power up is ok, set local state */ ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ /* Force pad isolation off if possible ++ (in case power never toggled) */ ++ if ((bus->ci->buscoretype == PCMCIA_CORE_ID) ++ && (bus->ci->buscorerev >= 10)) ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, 0, NULL); ++ ++ /* Make sure the controller has the bus up */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ ++ /* Send misc interrupt to indicate OOB not needed */ ++ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), ++ &retries); ++ if (retries <= retry_limit) ++ w_sdreg32(bus, SMB_DEV_INT, ++ offsetof(struct sdpcmd_regs, tosbmailbox), ++ &retries); ++ ++ if (retries > retry_limit) ++ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); ++ ++ /* Make sure we have SD bus access */ ++ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); ++ ++ /* Change state */ ++ bus->sleeping = false; ++ } ++ ++ return 0; ++} ++ ++static void bus_wake(struct brcmf_bus *bus) ++{ ++ if (bus->sleeping) ++ brcmf_sdbrcm_bussleep(bus, false); ++} ++ ++static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) ++{ ++ u32 intstatus = 0; ++ u32 hmb_data; ++ u8 fcbits; ++ uint retries = 0; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Read mailbox data and ack that we did so */ ++ r_sdreg32(bus, &hmb_data, ++ offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); ++ ++ if (retries <= retry_limit) ++ w_sdreg32(bus, SMB_INT_ACK, ++ offsetof(struct sdpcmd_regs, tosbmailbox), &retries); ++ bus->f1regdata += 2; ++ ++ /* Dongle recomposed rx frames, accept them again */ ++ if (hmb_data & HMB_DATA_NAKHANDLED) { ++ brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n", ++ bus->rx_seq); ++ if (!bus->rxskip) ++ brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n"); ++ ++ bus->rxskip = false; ++ intstatus |= I_HMB_FRAME_IND; ++ } ++ ++ /* ++ * DEVREADY does not occur with gSPI. ++ */ ++ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { ++ bus->sdpcm_ver = ++ (hmb_data & HMB_DATA_VERSION_MASK) >> ++ HMB_DATA_VERSION_SHIFT; ++ if (bus->sdpcm_ver != SDPCM_PROT_VERSION) ++ brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, " ++ "expecting %d\n", ++ bus->sdpcm_ver, SDPCM_PROT_VERSION); ++ else ++ brcmf_dbg(INFO, "Dongle ready, protocol version %d\n", ++ bus->sdpcm_ver); ++ } ++ ++ /* ++ * Flow Control has been moved into the RX headers and this out of band ++ * method isn't used any more. ++ * remaining backward compatible with older dongles. ++ */ ++ if (hmb_data & HMB_DATA_FC) { ++ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> ++ HMB_DATA_FCDATA_SHIFT; ++ ++ if (fcbits & ~bus->flowcontrol) ++ bus->fc_xoff++; ++ ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Shouldn't be any others */ ++ if (hmb_data & ~(HMB_DATA_DEVREADY | ++ HMB_DATA_NAKHANDLED | ++ HMB_DATA_FC | ++ HMB_DATA_FWREADY | ++ HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) ++ brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n", ++ hmb_data); ++ ++ return intstatus; ++} ++ ++static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) ++{ ++ uint retries = 0; ++ u16 lastrbc; ++ u8 hi, lo; ++ int err; ++ ++ brcmf_dbg(ERROR, "%sterminate frame%s\n", ++ abort ? "abort command, " : "", ++ rtx ? ", send NAK" : ""); ++ ++ if (abort) ++ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_FRAMECTRL, ++ SFC_RF_TERM, &err); ++ bus->f1regdata++; ++ ++ /* Wait until the packet has been flushed (device/FIFO stable) */ ++ for (lastrbc = retries = 0xffff; retries > 0; retries--) { ++ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_RFRAMEBCHI, NULL); ++ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_RFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ ++ if ((hi == 0) && (lo == 0)) ++ break; ++ ++ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { ++ brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n", ++ lastrbc, (hi << 8) + lo); ++ } ++ lastrbc = (hi << 8) + lo; ++ } ++ ++ if (!retries) ++ brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc); ++ else ++ brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); ++ ++ if (rtx) { ++ bus->rxrtx++; ++ w_sdreg32(bus, SMB_NAK, ++ offsetof(struct sdpcmd_regs, tosbmailbox), &retries); ++ ++ bus->f1regdata++; ++ if (retries <= retry_limit) ++ bus->rxskip = true; ++ } ++ ++ /* Clear partial in any case */ ++ bus->nextlen = 0; ++ ++ /* If we can't reach the device, signal failure */ ++ if (err || brcmf_sdcard_regfail(bus->sdiodev)) ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++} ++ ++static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) ++{ ++ u16 dlen, totlen; ++ u8 *dptr, num = 0; ++ ++ u16 sublen, check; ++ struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; ++ ++ int errcode; ++ u8 chan, seq, doff, sfdoff; ++ u8 txmax; ++ ++ int ifidx = 0; ++ bool usechain = bus->use_rxchain; ++ ++ /* If packets, issue read(s) and send up packet chain */ ++ /* Return sequence numbers consumed? */ ++ ++ brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom); ++ ++ /* If there's a descriptor, generate the packet chain */ ++ if (bus->glomd) { ++ pfirst = plast = pnext = NULL; ++ dlen = (u16) (bus->glomd->len); ++ dptr = bus->glomd->data; ++ if (!dlen || (dlen & 1)) { ++ brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n", ++ dlen); ++ dlen = 0; ++ } ++ ++ for (totlen = num = 0; dlen; num++) { ++ /* Get (and move past) next length */ ++ sublen = get_unaligned_le16(dptr); ++ dlen -= sizeof(u16); ++ dptr += sizeof(u16); ++ if ((sublen < SDPCM_HDRLEN) || ++ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { ++ brcmf_dbg(ERROR, "descriptor len %d bad: %d\n", ++ num, sublen); ++ pnext = NULL; ++ break; ++ } ++ if (sublen % BRCMF_SDALIGN) { ++ brcmf_dbg(ERROR, "sublen %d not multiple of %d\n", ++ sublen, BRCMF_SDALIGN); ++ usechain = false; ++ } ++ totlen += sublen; ++ ++ /* For last frame, adjust read len so total ++ is a block multiple */ ++ if (!dlen) { ++ sublen += ++ (roundup(totlen, bus->blocksize) - totlen); ++ totlen = roundup(totlen, bus->blocksize); ++ } ++ ++ /* Allocate/chain packet for next subframe */ ++ pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); ++ if (pnext == NULL) { ++ brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n", ++ num, sublen); ++ break; ++ } ++ if (!pfirst) { ++ pfirst = plast = pnext; ++ } else { ++ plast->next = pnext; ++ plast = pnext; ++ } ++ ++ /* Adhere to start alignment requirements */ ++ pkt_align(pnext, sublen, BRCMF_SDALIGN); ++ } ++ ++ /* If all allocations succeeded, save packet chain ++ in bus structure */ ++ if (pnext) { ++ brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", ++ totlen, num); ++ if (BRCMF_GLOM_ON() && bus->nextlen && ++ totlen != bus->nextlen) { ++ brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", ++ bus->nextlen, totlen, rxseq); ++ } ++ bus->glom = pfirst; ++ pfirst = pnext = NULL; ++ } else { ++ if (pfirst) ++ brcmu_pkt_buf_free_skb(pfirst); ++ bus->glom = NULL; ++ num = 0; ++ } ++ ++ /* Done with descriptor packet */ ++ brcmu_pkt_buf_free_skb(bus->glomd); ++ bus->glomd = NULL; ++ bus->nextlen = 0; ++ } ++ ++ /* Ok -- either we just generated a packet chain, ++ or had one from before */ ++ if (bus->glom) { ++ if (BRCMF_GLOM_ON()) { ++ brcmf_dbg(GLOM, "try superframe read, packet chain:\n"); ++ for (pnext = bus->glom; pnext; pnext = pnext->next) { ++ brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n", ++ pnext, (u8 *) (pnext->data), ++ pnext->len, pnext->len); ++ } ++ } ++ ++ pfirst = bus->glom; ++ dlen = (u16) brcmu_pkttotlen(pfirst); ++ ++ /* Do an SDIO read for the superframe. Configurable iovar to ++ * read directly into the chained packet, or allocate a large ++ * packet and and copy into the chain. ++ */ ++ if (usechain) { ++ errcode = brcmf_sdcard_recv_buf(bus->sdiodev, ++ bus->sdiodev->sbwad, ++ SDIO_FUNC_2, ++ F2SYNC, (u8 *) pfirst->data, dlen, ++ pfirst); ++ } else if (bus->dataptr) { ++ errcode = brcmf_sdcard_recv_buf(bus->sdiodev, ++ bus->sdiodev->sbwad, ++ SDIO_FUNC_2, ++ F2SYNC, bus->dataptr, dlen, ++ NULL); ++ sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen, ++ bus->dataptr); ++ if (sublen != dlen) { ++ brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", ++ dlen, sublen); ++ errcode = -1; ++ } ++ pnext = NULL; ++ } else { ++ brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", ++ dlen); ++ errcode = -1; ++ } ++ bus->f2rxdata++; ++ ++ /* On failure, kill the superframe, allow a couple retries */ ++ if (errcode < 0) { ++ brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n", ++ dlen, errcode); ++ bus->drvr->rx_errors++; ++ ++ if (bus->glomerr++ < 3) { ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ } else { ++ bus->glomerr = 0; ++ brcmf_sdbrcm_rxfail(bus, true, false); ++ brcmu_pkt_buf_free_skb(bus->glom); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ return 0; ++ } ++#ifdef BCMDBG ++ if (BRCMF_GLOM_ON()) { ++ printk(KERN_DEBUG "SUPERFRAME:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ pfirst->data, min_t(int, pfirst->len, 48)); ++ } ++#endif ++ ++ /* Validate the superframe header */ ++ dptr = (u8 *) (pfirst->data); ++ sublen = get_unaligned_le16(dptr); ++ check = get_unaligned_le16(dptr + sizeof(u16)); ++ ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", ++ bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ errcode = 0; ++ if ((u16)~(sublen ^ check)) { ++ brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", ++ sublen, check); ++ errcode = -1; ++ } else if (roundup(sublen, bus->blocksize) != dlen) { ++ brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", ++ sublen, roundup(sublen, bus->blocksize), ++ dlen); ++ errcode = -1; ++ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != ++ SDPCM_GLOM_CHANNEL) { ++ brcmf_dbg(ERROR, "(superframe): bad channel %d\n", ++ SDPCM_PACKET_CHANNEL( ++ &dptr[SDPCM_FRAMETAG_LEN])); ++ errcode = -1; ++ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { ++ brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN) || ++ (doff > (pfirst->len - SDPCM_HDRLEN))) { ++ brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", ++ doff, sublen, pfirst->len, SDPCM_HDRLEN); ++ errcode = -1; ++ } ++ ++ /* Check sequence number of superframe SW header */ ++ if (rxseq != seq) { ++ brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", ++ seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((u8) (txmax - bus->tx_seq) > 0x40) { ++ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", ++ txmax, bus->tx_seq); ++ txmax = bus->tx_seq + 2; ++ } ++ bus->tx_max = txmax; ++ ++ /* Remove superframe header, remember offset */ ++ skb_pull(pfirst, doff); ++ sfdoff = doff; ++ ++ /* Validate all the subframe headers */ ++ for (num = 0, pnext = pfirst; pnext && !errcode; ++ num++, pnext = pnext->next) { ++ dptr = (u8 *) (pnext->data); ++ dlen = (u16) (pnext->len); ++ sublen = get_unaligned_le16(dptr); ++ check = get_unaligned_le16(dptr + sizeof(u16)); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++#ifdef BCMDBG ++ if (BRCMF_GLOM_ON()) { ++ printk(KERN_DEBUG "subframe:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ dptr, 32); ++ } ++#endif ++ ++ if ((u16)~(sublen ^ check)) { ++ brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", ++ num, sublen, check); ++ errcode = -1; ++ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { ++ brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n", ++ num, sublen, dlen); ++ errcode = -1; ++ } else if ((chan != SDPCM_DATA_CHANNEL) && ++ (chan != SDPCM_EVENT_CHANNEL)) { ++ brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n", ++ num, chan); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { ++ brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n", ++ num, doff, sublen, SDPCM_HDRLEN); ++ errcode = -1; ++ } ++ } ++ ++ if (errcode) { ++ /* Terminate frame on error, request ++ a couple retries */ ++ if (bus->glomerr++ < 3) { ++ /* Restore superframe header space */ ++ skb_push(pfirst, sfdoff); ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ } else { ++ bus->glomerr = 0; ++ brcmf_sdbrcm_rxfail(bus, true, false); ++ brcmu_pkt_buf_free_skb(bus->glom); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ bus->nextlen = 0; ++ return 0; ++ } ++ ++ /* Basic SD framing looks ok - process each packet (header) */ ++ save_pfirst = pfirst; ++ bus->glom = NULL; ++ plast = NULL; ++ ++ for (num = 0; pfirst; rxseq++, pfirst = pnext) { ++ pnext = pfirst->next; ++ pfirst->next = NULL; ++ ++ dptr = (u8 *) (pfirst->data); ++ sublen = get_unaligned_le16(dptr); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", ++ num, pfirst, pfirst->data, ++ pfirst->len, sublen, chan, seq); ++ ++ /* precondition: chan == SDPCM_DATA_CHANNEL || ++ chan == SDPCM_EVENT_CHANNEL */ ++ ++ if (rxseq != seq) { ++ brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", ++ seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { ++ printk(KERN_DEBUG "Rx Subframe Data:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ dptr, dlen); ++ } ++#endif ++ ++ __skb_trim(pfirst, sublen); ++ skb_pull(pfirst, doff); ++ ++ if (pfirst->len == 0) { ++ brcmu_pkt_buf_free_skb(pfirst); ++ if (plast) ++ plast->next = pnext; ++ else ++ save_pfirst = pnext; ++ ++ continue; ++ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, ++ pfirst) != 0) { ++ brcmf_dbg(ERROR, "rx protocol error\n"); ++ bus->drvr->rx_errors++; ++ brcmu_pkt_buf_free_skb(pfirst); ++ if (plast) ++ plast->next = pnext; ++ else ++ save_pfirst = pnext; ++ ++ continue; ++ } ++ ++ /* this packet will go up, link back into ++ chain and count it */ ++ pfirst->next = pnext; ++ plast = pfirst; ++ num++; ++ ++#ifdef BCMDBG ++ if (BRCMF_GLOM_ON()) { ++ brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", ++ num, pfirst, pfirst->data, ++ pfirst->len, pfirst->next, ++ pfirst->prev); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ pfirst->data, ++ min_t(int, pfirst->len, 32)); ++ } ++#endif /* BCMDBG */ ++ } ++ if (num) { ++ up(&bus->sdsem); ++ brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); ++ down(&bus->sdsem); ++ } ++ ++ bus->rxglomframes++; ++ bus->rxglompkts += num; ++ } ++ return num; ++} ++ ++static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, ++ bool *pending) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); ++ ++ /* Wait until control frame is available */ ++ add_wait_queue(&bus->dcmd_resp_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!(*condition) && (!signal_pending(current) && timeout)) ++ timeout = schedule_timeout(timeout); ++ ++ if (signal_pending(current)) ++ *pending = true; ++ ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&bus->dcmd_resp_wait, &wait); ++ ++ return timeout; ++} ++ ++static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) ++{ ++ if (waitqueue_active(&bus->dcmd_resp_wait)) ++ wake_up_interruptible(&bus->dcmd_resp_wait); ++ ++ return 0; ++} ++static void ++brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) ++{ ++ uint rdlen, pad; ++ ++ int sdret; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Set rxctl for frame (w/optional alignment) */ ++ bus->rxctl = bus->rxbuf; ++ bus->rxctl += BRCMF_FIRSTREAD; ++ pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); ++ if (pad) ++ bus->rxctl += (BRCMF_SDALIGN - pad); ++ bus->rxctl -= BRCMF_FIRSTREAD; ++ ++ /* Copy the already-read portion over */ ++ memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); ++ if (len <= BRCMF_FIRSTREAD) ++ goto gotpkt; ++ ++ /* Raise rdlen to next SDIO block to avoid tail command */ ++ rdlen = len - BRCMF_FIRSTREAD; ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((len + pad) < bus->drvr->maxctl)) ++ rdlen += pad; ++ } else if (rdlen % BRCMF_SDALIGN) { ++ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (rdlen & (ALIGNMENT - 1)) ++ rdlen = roundup(rdlen, ALIGNMENT); ++ ++ /* Drop if the read is too big or it exceeds our maximum */ ++ if ((rdlen + BRCMF_FIRSTREAD) > bus->drvr->maxctl) { ++ brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n", ++ rdlen, bus->drvr->maxctl); ++ bus->drvr->rx_errors++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ goto done; ++ } ++ ++ if ((len - doff) > bus->drvr->maxctl) { ++ brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", ++ len, len - doff, bus->drvr->maxctl); ++ bus->drvr->rx_errors++; ++ bus->rx_toolong++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ goto done; ++ } ++ ++ /* Read remainder of frame body into the rxctl buffer */ ++ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, ++ bus->sdiodev->sbwad, ++ SDIO_FUNC_2, ++ F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen, ++ NULL); ++ bus->f2rxdata++; ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", ++ rdlen, sdret); ++ bus->rxc_errors++; ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ goto done; ++ } ++ ++gotpkt: ++ ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { ++ printk(KERN_DEBUG "RxCtrl:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len); ++ } ++#endif ++ ++ /* Point to valid data and indicate its length */ ++ bus->rxctl += doff; ++ bus->rxlen = len - doff; ++ ++done: ++ /* Awake any waiters */ ++ brcmf_sdbrcm_dcmd_resp_wake(bus); ++} ++ ++/* Pad read to blocksize for efficiency */ ++static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) ++{ ++ if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { ++ *pad = bus->blocksize - (*rdlen % bus->blocksize); ++ if (*pad <= bus->roundup && *pad < bus->blocksize && ++ *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ) ++ *rdlen += *pad; ++ } else if (*rdlen % BRCMF_SDALIGN) { ++ *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); ++ } ++} ++ ++static void ++brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, ++ struct sk_buff **pkt, u8 **rxbuf) ++{ ++ int sdret; /* Return code from calls */ ++ ++ *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); ++ if (*pkt == NULL) ++ return; ++ ++ pkt_align(*pkt, rdlen, BRCMF_SDALIGN); ++ *rxbuf = (u8 *) ((*pkt)->data); ++ /* Read the entire frame */ ++ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, ++ *rxbuf, rdlen, *pkt); ++ bus->f2rxdata++; ++ ++ if (sdret < 0) { ++ brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", ++ rdlen, sdret); ++ brcmu_pkt_buf_free_skb(*pkt); ++ bus->drvr->rx_errors++; ++ /* Force retry w/normal header read. ++ * Don't attempt NAK for ++ * gSPI ++ */ ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ *pkt = NULL; ++ } ++} ++ ++/* Checks the header */ ++static int ++brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf, ++ u8 rxseq, u16 nextlen, u16 *len) ++{ ++ u16 check; ++ bool len_consistent; /* Result of comparing readahead len and ++ len from hw-hdr */ ++ ++ memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); ++ ++ /* Extract hardware header fields */ ++ *len = get_unaligned_le16(bus->rxhdr); ++ check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); ++ ++ /* All zeros means readahead info was bad */ ++ if (!(*len | check)) { ++ brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); ++ goto fail; ++ } ++ ++ /* Validate check bytes */ ++ if ((u16)~(*len ^ check)) { ++ brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", ++ nextlen, *len, check); ++ bus->rx_badhdr++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ goto fail; ++ } ++ ++ /* Validate frame length */ ++ if (*len < SDPCM_HDRLEN) { ++ brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", ++ *len); ++ goto fail; ++ } ++ ++ /* Check for consistency with readahead info */ ++ len_consistent = (nextlen != (roundup(*len, 16) >> 4)); ++ if (len_consistent) { ++ /* Mismatch, force retry w/normal ++ header (may be >4K) */ ++ brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", ++ nextlen, *len, roundup(*len, 16), ++ rxseq); ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ brcmf_sdbrcm_pktfree2(bus, pkt); ++ return -EINVAL; ++} ++ ++/* Return true if there may be more frames to read */ ++static uint ++brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) ++{ ++ u16 len, check; /* Extracted hardware header fields */ ++ u8 chan, seq, doff; /* Extracted software header fields */ ++ u8 fcbits; /* Extracted fcbits from software header */ ++ ++ struct sk_buff *pkt; /* Packet for event or data frames */ ++ u16 pad; /* Number of pad bytes to read */ ++ u16 rdlen; /* Total number of bytes to read */ ++ u8 rxseq; /* Next sequence number to expect */ ++ uint rxleft = 0; /* Remaining number of frames allowed */ ++ int sdret; /* Return code from calls */ ++ u8 txmax; /* Maximum tx sequence offered */ ++ u8 *rxbuf; ++ int ifidx = 0; ++ uint rxcount = 0; /* Total frames read */ ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Not finished unless we encounter no more frames indication */ ++ *finished = false; ++ ++ for (rxseq = bus->rx_seq, rxleft = maxframes; ++ !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; ++ rxseq++, rxleft--) { ++ ++ /* Handle glomming separately */ ++ if (bus->glom || bus->glomd) { ++ u8 cnt; ++ brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", ++ bus->glomd, bus->glom); ++ cnt = brcmf_sdbrcm_rxglom(bus, rxseq); ++ brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); ++ rxseq += cnt - 1; ++ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; ++ continue; ++ } ++ ++ /* Try doing single read if we can */ ++ if (bus->nextlen) { ++ u16 nextlen = bus->nextlen; ++ bus->nextlen = 0; ++ ++ rdlen = len = nextlen << 4; ++ brcmf_pad(bus, &pad, &rdlen); ++ ++ /* ++ * After the frame is received we have to ++ * distinguish whether it is data ++ * or non-data frame. ++ */ ++ brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); ++ if (pkt == NULL) { ++ /* Give up on data, request rtx of events */ ++ brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", ++ len, rdlen, rxseq); ++ continue; ++ } ++ ++ if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, ++ &len) < 0) ++ continue; ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL( ++ &bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE( ++ &bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE( ++ &bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE( ++ &bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ bus->nextlen = ++ bus->rxhdr[SDPCM_FRAMETAG_LEN + ++ SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", ++ bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ ++ bus->drvr->rx_readahead_cnt++; ++ ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE( ++ &bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ if (bus->flowcontrol != fcbits) { ++ if (~bus->flowcontrol & fcbits) ++ bus->fc_xoff++; ++ ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", ++ seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((u8) (txmax - bus->tx_seq) > 0x40) { ++ brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", ++ txmax, bus->tx_seq); ++ txmax = bus->tx_seq + 2; ++ } ++ bus->tx_max = txmax; ++ ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { ++ printk(KERN_DEBUG "Rx Data:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ rxbuf, len); ++ } else if (BRCMF_HDRS_ON()) { ++ printk(KERN_DEBUG "RxHdr:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ bus->rxhdr, SDPCM_HDRLEN); ++ } ++#endif ++ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", ++ seq); ++ /* Force retry w/normal header read */ ++ bus->nextlen = 0; ++ brcmf_sdbrcm_rxfail(bus, false, true); ++ brcmf_sdbrcm_pktfree2(bus, pkt); ++ continue; ++ } ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN) || (doff > len)) { ++ brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", ++ doff, len, SDPCM_HDRLEN); ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ brcmf_sdbrcm_pktfree2(bus, pkt); ++ continue; ++ } ++ ++ /* All done with this one -- now deliver the packet */ ++ goto deliver; ++ } ++ ++ /* Read frame header (hardware and software) */ ++ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, bus->rxhdr, ++ BRCMF_FIRSTREAD, NULL); ++ bus->f2rxhdrs++; ++ ++ if (sdret < 0) { ++ brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); ++ bus->rx_hdrfail++; ++ brcmf_sdbrcm_rxfail(bus, true, true); ++ continue; ++ } ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) { ++ printk(KERN_DEBUG "RxHdr:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ bus->rxhdr, SDPCM_HDRLEN); ++ } ++#endif ++ ++ /* Extract hardware header fields */ ++ len = get_unaligned_le16(bus->rxhdr); ++ check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); ++ ++ /* All zeros means no more frames */ ++ if (!(len | check)) { ++ *finished = true; ++ break; ++ } ++ ++ /* Validate check bytes */ ++ if ((u16) ~(len ^ check)) { ++ brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", ++ len, check); ++ bus->rx_badhdr++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN) { ++ brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); ++ continue; ++ } ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN) || (doff > len)) { ++ brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", ++ doff, len, SDPCM_HDRLEN, seq); ++ bus->rx_badhdr++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ continue; ++ } ++ ++ /* Save the readahead length if there is one */ ++ bus->nextlen = ++ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", ++ bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ if (bus->flowcontrol != fcbits) { ++ if (~bus->flowcontrol & fcbits) ++ bus->fc_xoff++; ++ ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((u8) (txmax - bus->tx_seq) > 0x40) { ++ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", ++ txmax, bus->tx_seq); ++ txmax = bus->tx_seq + 2; ++ } ++ bus->tx_max = txmax; ++ ++ /* Call a separate function for control frames */ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); ++ continue; ++ } ++ ++ /* precondition: chan is either SDPCM_DATA_CHANNEL, ++ SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or ++ SDPCM_GLOM_CHANNEL */ ++ ++ /* Length to read */ ++ rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; ++ ++ /* May pad read to blocksize for efficiency */ ++ if (bus->roundup && bus->blocksize && ++ (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) ++ rdlen += pad; ++ } else if (rdlen % BRCMF_SDALIGN) { ++ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (rdlen & (ALIGNMENT - 1)) ++ rdlen = roundup(rdlen, ALIGNMENT); ++ ++ if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { ++ /* Too long -- skip this frame */ ++ brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", ++ len, rdlen); ++ bus->drvr->rx_errors++; ++ bus->rx_toolong++; ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ continue; ++ } ++ ++ pkt = brcmu_pkt_buf_get_skb(rdlen + ++ BRCMF_FIRSTREAD + BRCMF_SDALIGN); ++ if (!pkt) { ++ /* Give up on data, request rtx of events */ ++ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", ++ rdlen, chan); ++ bus->drvr->rx_dropped++; ++ brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); ++ continue; ++ } ++ ++ /* Leave room for what we already read, and align remainder */ ++ skb_pull(pkt, BRCMF_FIRSTREAD); ++ pkt_align(pkt, rdlen, BRCMF_SDALIGN); ++ ++ /* Read the remaining frame data */ ++ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), ++ rdlen, pkt); ++ bus->f2rxdata++; ++ ++ if (sdret < 0) { ++ brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, ++ ((chan == SDPCM_EVENT_CHANNEL) ? "event" ++ : ((chan == SDPCM_DATA_CHANNEL) ? "data" ++ : "test")), sdret); ++ brcmu_pkt_buf_free_skb(pkt); ++ bus->drvr->rx_errors++; ++ brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); ++ continue; ++ } ++ ++ /* Copy the already-read portion */ ++ skb_push(pkt, BRCMF_FIRSTREAD); ++ memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); ++ ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { ++ printk(KERN_DEBUG "Rx Data:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ pkt->data, len); ++ } ++#endif ++ ++deliver: ++ /* Save superframe descriptor and allocate packet frame */ ++ if (chan == SDPCM_GLOM_CHANNEL) { ++ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { ++ brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", ++ len); ++#ifdef BCMDBG ++ if (BRCMF_GLOM_ON()) { ++ printk(KERN_DEBUG "Glom Data:\n"); ++ print_hex_dump_bytes("", ++ DUMP_PREFIX_OFFSET, ++ pkt->data, len); ++ } ++#endif ++ __skb_trim(pkt, len); ++ skb_pull(pkt, SDPCM_HDRLEN); ++ bus->glomd = pkt; ++ } else { ++ brcmf_dbg(ERROR, "%s: glom superframe w/o " ++ "descriptor!\n", __func__); ++ brcmf_sdbrcm_rxfail(bus, false, false); ++ } ++ continue; ++ } ++ ++ /* Fill in packet len and prio, deliver upward */ ++ __skb_trim(pkt, len); ++ skb_pull(pkt, doff); ++ ++ if (pkt->len == 0) { ++ brcmu_pkt_buf_free_skb(pkt); ++ continue; ++ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) { ++ brcmf_dbg(ERROR, "rx protocol error\n"); ++ brcmu_pkt_buf_free_skb(pkt); ++ bus->drvr->rx_errors++; ++ continue; ++ } ++ ++ /* Unlock during rx call */ ++ up(&bus->sdsem); ++ brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); ++ down(&bus->sdsem); ++ } ++ rxcount = maxframes - rxleft; ++#ifdef BCMDBG ++ /* Message if we hit the limit */ ++ if (!rxleft) ++ brcmf_dbg(DATA, "hit rx limit of %d frames\n", ++ maxframes); ++ else ++#endif /* BCMDBG */ ++ brcmf_dbg(DATA, "processed %d frames\n", rxcount); ++ /* Back off rxseq if awaiting rtx, update rx_seq */ ++ if (bus->rxskip) ++ rxseq--; ++ bus->rx_seq = rxseq; ++ ++ return rxcount; ++} ++ ++static int ++brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags, ++ u8 *buf, uint nbytes, struct sk_buff *pkt) ++{ ++ return brcmf_sdcard_send_buf ++ (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt); ++} ++ ++static void ++brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) ++{ ++ up(&bus->sdsem); ++ wait_event_interruptible_timeout(bus->ctrl_wait, ++ (*lockvar == false), HZ * 2); ++ down(&bus->sdsem); ++ return; ++} ++ ++static void ++brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) ++{ ++ if (waitqueue_active(&bus->ctrl_wait)) ++ wake_up_interruptible(&bus->ctrl_wait); ++ return; ++} ++ ++/* Writes a HW/SW header into the packet and sends it. */ ++/* Assumes: (a) header space already there, (b) caller holds lock */ ++static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, ++ uint chan, bool free_pkt) ++{ ++ int ret; ++ u8 *frame; ++ u16 len, pad = 0; ++ u32 swheader; ++ struct sk_buff *new; ++ int i; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ frame = (u8 *) (pkt->data); ++ ++ /* Add alignment padding, allocate new packet if needed */ ++ pad = ((unsigned long)frame % BRCMF_SDALIGN); ++ if (pad) { ++ if (skb_headroom(pkt) < pad) { ++ brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n", ++ skb_headroom(pkt), pad); ++ bus->drvr->tx_realloc++; ++ new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN); ++ if (!new) { ++ brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n", ++ pkt->len + BRCMF_SDALIGN); ++ ret = -ENOMEM; ++ goto done; ++ } ++ ++ pkt_align(new, pkt->len, BRCMF_SDALIGN); ++ memcpy(new->data, pkt->data, pkt->len); ++ if (free_pkt) ++ brcmu_pkt_buf_free_skb(pkt); ++ /* free the pkt if canned one is not used */ ++ free_pkt = true; ++ pkt = new; ++ frame = (u8 *) (pkt->data); ++ /* precondition: (frame % BRCMF_SDALIGN) == 0) */ ++ pad = 0; ++ } else { ++ skb_push(pkt, pad); ++ frame = (u8 *) (pkt->data); ++ /* precondition: pad + SDPCM_HDRLEN <= pkt->len */ ++ memset(frame, 0, pad + SDPCM_HDRLEN); ++ } ++ } ++ /* precondition: pad < BRCMF_SDALIGN */ ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ len = (u16) (pkt->len); ++ *(__le16 *) frame = cpu_to_le16(len); ++ *(((__le16 *) frame) + 1) = cpu_to_le16(~len); ++ ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ++ ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | ++ (((pad + ++ SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ ++ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); ++ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ ++#ifdef BCMDBG ++ tx_packets[pkt->priority]++; ++ if (BRCMF_BYTES_ON() && ++ (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || ++ (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { ++ printk(KERN_DEBUG "Tx Frame:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len); ++ } else if (BRCMF_HDRS_ON()) { ++ printk(KERN_DEBUG "TxHdr:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ frame, min_t(u16, len, 16)); ++ } ++#endif ++ ++ /* Raise len to next SDIO block to eliminate tail command */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ u16 pad = bus->blocksize - (len % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize)) ++ len += pad; ++ } else if (len % BRCMF_SDALIGN) { ++ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); ++ } ++ ++ /* Some controllers have trouble with odd bytes -- round to even */ ++ if (len & (ALIGNMENT - 1)) ++ len = roundup(len, ALIGNMENT); ++ ++ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, frame, ++ len, pkt); ++ bus->f2txdata++; ++ ++ if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ++ ret); ++ bus->tx_sderrs++; ++ ++ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, ++ NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ u8 hi, lo; ++ hi = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, ++ NULL); ++ lo = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, ++ NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ ++ } ++ if (ret == 0) ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ ++done: ++ /* restore pkt buffer pointer before calling tx complete routine */ ++ skb_pull(pkt, SDPCM_HDRLEN + pad); ++ up(&bus->sdsem); ++ brcmf_txcomplete(bus->drvr, pkt, ret != 0); ++ down(&bus->sdsem); ++ ++ if (free_pkt) ++ brcmu_pkt_buf_free_skb(pkt); ++ ++ return ret; ++} ++ ++static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) ++{ ++ struct sk_buff *pkt; ++ u32 intstatus = 0; ++ uint retries = 0; ++ int ret = 0, prec_out; ++ uint cnt = 0; ++ uint datalen; ++ u8 tx_prec_map; ++ ++ struct brcmf_pub *drvr = bus->drvr; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ tx_prec_map = ~bus->flowcontrol; ++ ++ /* Send frames until the limit or some other event */ ++ for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { ++ spin_lock_bh(&bus->txqlock); ++ pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); ++ if (pkt == NULL) { ++ spin_unlock_bh(&bus->txqlock); ++ break; ++ } ++ spin_unlock_bh(&bus->txqlock); ++ datalen = pkt->len - SDPCM_HDRLEN; ++ ++ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); ++ if (ret) ++ bus->drvr->tx_errors++; ++ else ++ bus->drvr->dstats.tx_bytes += datalen; ++ ++ /* In poll mode, need to check for other events */ ++ if (!bus->intr && cnt) { ++ /* Check device status, signal pending interrupt */ ++ r_sdreg32(bus, &intstatus, ++ offsetof(struct sdpcmd_regs, intstatus), ++ &retries); ++ bus->f2txdata++; ++ if (brcmf_sdcard_regfail(bus->sdiodev)) ++ break; ++ if (intstatus & bus->hostintmask) ++ bus->ipend = true; ++ } ++ } ++ ++ /* Deflow-control stack if needed */ ++ if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && ++ drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) ++ brcmf_txflowcontrol(drvr, 0, OFF); ++ ++ return cnt; ++} ++ ++static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) ++{ ++ u32 intstatus, newstatus = 0; ++ uint retries = 0; ++ uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ ++ uint txlimit = bus->txbound; /* Tx frames to send before resched */ ++ uint framecnt = 0; /* Temporary counter of tx/rx frames */ ++ bool rxdone = true; /* Flag for no more read data */ ++ bool resched = false; /* Flag indicating resched wanted */ ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Start with leftover status bits */ ++ intstatus = bus->intstatus; ++ ++ down(&bus->sdsem); ++ ++ /* If waiting for HTAVAIL, check status */ ++ if (bus->clkstate == CLK_PENDING) { ++ int err; ++ u8 clkctl, devctl = 0; ++ ++#ifdef BCMDBG ++ /* Check for inconsistent device control */ ++ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ } ++#endif /* BCMDBG */ ++ ++ /* Read CSR, if clock on switch to AVAIL, else ignore */ ++ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "error reading CSR: %d\n", ++ err); ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ } ++ ++ brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", ++ devctl, clkctl); ++ ++ if (SBSDIO_HTAV(clkctl)) { ++ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", ++ err); ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ } ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_DEVICE_CTL, devctl, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", ++ err); ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ } ++ bus->clkstate = CLK_AVAIL; ++ } else { ++ goto clkwait; ++ } ++ } ++ ++ bus_wake(bus); ++ ++ /* Make sure backplane clock is on */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); ++ if (bus->clkstate == CLK_PENDING) ++ goto clkwait; ++ ++ /* Pending interrupt indicates new device status */ ++ if (bus->ipend) { ++ bus->ipend = false; ++ r_sdreg32(bus, &newstatus, ++ offsetof(struct sdpcmd_regs, intstatus), &retries); ++ bus->f1regdata++; ++ if (brcmf_sdcard_regfail(bus->sdiodev)) ++ newstatus = 0; ++ newstatus &= bus->hostintmask; ++ bus->fcstate = !!(newstatus & I_HMB_FC_STATE); ++ if (newstatus) { ++ w_sdreg32(bus, newstatus, ++ offsetof(struct sdpcmd_regs, intstatus), ++ &retries); ++ bus->f1regdata++; ++ } ++ } ++ ++ /* Merge new bits with previous */ ++ intstatus |= newstatus; ++ bus->intstatus = 0; ++ ++ /* Handle flow-control change: read new state in case our ack ++ * crossed another change interrupt. If change still set, assume ++ * FC ON for safety, let next loop through do the debounce. ++ */ ++ if (intstatus & I_HMB_FC_CHANGE) { ++ intstatus &= ~I_HMB_FC_CHANGE; ++ w_sdreg32(bus, I_HMB_FC_CHANGE, ++ offsetof(struct sdpcmd_regs, intstatus), &retries); ++ ++ r_sdreg32(bus, &newstatus, ++ offsetof(struct sdpcmd_regs, intstatus), &retries); ++ bus->f1regdata += 2; ++ bus->fcstate = ++ !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); ++ intstatus |= (newstatus & bus->hostintmask); ++ } ++ ++ /* Handle host mailbox indication */ ++ if (intstatus & I_HMB_HOST_INT) { ++ intstatus &= ~I_HMB_HOST_INT; ++ intstatus |= brcmf_sdbrcm_hostmail(bus); ++ } ++ ++ /* Generally don't ask for these, can get CRC errors... */ ++ if (intstatus & I_WR_OOSYNC) { ++ brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); ++ intstatus &= ~I_WR_OOSYNC; ++ } ++ ++ if (intstatus & I_RD_OOSYNC) { ++ brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n"); ++ intstatus &= ~I_RD_OOSYNC; ++ } ++ ++ if (intstatus & I_SBINT) { ++ brcmf_dbg(ERROR, "Dongle reports SBINT\n"); ++ intstatus &= ~I_SBINT; ++ } ++ ++ /* Would be active due to wake-wlan in gSPI */ ++ if (intstatus & I_CHIPACTIVE) { ++ brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n"); ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Ignore frame indications if rxskip is set */ ++ if (bus->rxskip) ++ intstatus &= ~I_HMB_FRAME_IND; ++ ++ /* On frame indication, read available frames */ ++ if (PKT_AVAILABLE()) { ++ framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); ++ if (rxdone || bus->rxskip) ++ intstatus &= ~I_HMB_FRAME_IND; ++ rxlimit -= min(framecnt, rxlimit); ++ } ++ ++ /* Keep still-pending events for next scheduling */ ++ bus->intstatus = intstatus; ++ ++clkwait: ++ if (data_ok(bus) && bus->ctrl_frame_stat && ++ (bus->clkstate == CLK_AVAIL)) { ++ int ret, i; ++ ++ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, ++ (u32) bus->ctrl_frame_len, NULL); ++ ++ if (ret < 0) { ++ /* On failure, abort the command and ++ terminate the frame */ ++ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ++ ret); ++ bus->tx_sderrs++; ++ ++ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, ++ NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ u8 hi, lo; ++ hi = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, ++ NULL); ++ lo = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, ++ NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ ++ } ++ if (ret == 0) ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ ++ brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); ++ bus->ctrl_frame_stat = false; ++ brcmf_sdbrcm_wait_event_wakeup(bus); ++ } ++ /* Send queued frames (limit 1 if rx may still be pending) */ ++ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit ++ && data_ok(bus)) { ++ framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); ++ framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); ++ txlimit -= framecnt; ++ } ++ ++ /* Resched if events or tx frames are pending, ++ else await next interrupt */ ++ /* On failed register access, all bets are off: ++ no resched or interrupts */ ++ if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || ++ brcmf_sdcard_regfail(bus->sdiodev)) { ++ brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", ++ brcmf_sdcard_regfail(bus->sdiodev)); ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ bus->intstatus = 0; ++ } else if (bus->clkstate == CLK_PENDING) { ++ brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); ++ resched = true; ++ } else if (bus->intstatus || bus->ipend || ++ (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) ++ && data_ok(bus)) || PKT_AVAILABLE()) { ++ resched = true; ++ } ++ ++ bus->dpc_sched = resched; ++ ++ /* If we're done for now, turn off clock request. */ ++ if ((bus->clkstate != CLK_PENDING) ++ && bus->idletime == BRCMF_IDLE_IMMEDIATE) { ++ bus->activity = false; ++ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); ++ } ++ ++ up(&bus->sdsem); ++ ++ return resched; ++} ++ ++static int brcmf_sdbrcm_dpc_thread(void *data) ++{ ++ struct brcmf_bus *bus = (struct brcmf_bus *) data; ++ ++ allow_signal(SIGTERM); ++ /* Run until signal received */ ++ while (1) { ++ if (kthread_should_stop()) ++ break; ++ if (!wait_for_completion_interruptible(&bus->dpc_wait)) { ++ /* Call bus dpc unless it indicated down ++ (then clean stop) */ ++ if (bus->drvr->busstate != BRCMF_BUS_DOWN) { ++ if (brcmf_sdbrcm_dpc(bus)) ++ complete(&bus->dpc_wait); ++ } else { ++ /* after stopping the bus, exit thread */ ++ brcmf_sdbrcm_bus_stop(bus); ++ bus->dpc_tsk = NULL; ++ break; ++ } ++ } else ++ break; ++ } ++ return 0; ++} ++ ++int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) ++{ ++ int ret = -EBADE; ++ uint datalen, prec; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ datalen = pkt->len; ++ ++ /* Add space for the header */ ++ skb_push(pkt, SDPCM_HDRLEN); ++ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ ++ ++ prec = prio2prec((pkt->priority & PRIOMASK)); ++ ++ /* Check for existing queue, current flow-control, ++ pending event, or pending clock */ ++ brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq)); ++ bus->fcqueued++; ++ ++ /* Priority based enq */ ++ spin_lock_bh(&bus->txqlock); ++ if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) { ++ skb_pull(pkt, SDPCM_HDRLEN); ++ brcmf_txcomplete(bus->drvr, pkt, false); ++ brcmu_pkt_buf_free_skb(pkt); ++ brcmf_dbg(ERROR, "out of bus->txq !!!\n"); ++ ret = -ENOSR; ++ } else { ++ ret = 0; ++ } ++ spin_unlock_bh(&bus->txqlock); ++ ++ if (pktq_len(&bus->txq) >= TXHI) ++ brcmf_txflowcontrol(bus->drvr, 0, ON); ++ ++#ifdef BCMDBG ++ if (pktq_plen(&bus->txq, prec) > qcount[prec]) ++ qcount[prec] = pktq_plen(&bus->txq, prec); ++#endif ++ /* Schedule DPC if needed to send queued packet(s) */ ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = true; ++ if (bus->dpc_tsk) ++ complete(&bus->dpc_wait); ++ } ++ ++ return ret; ++} ++ ++static int ++brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, ++ uint size) ++{ ++ int bcmerror = 0; ++ u32 sdaddr; ++ uint dsize; ++ ++ /* Determine initial transfer parameters */ ++ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; ++ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) ++ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); ++ else ++ dsize = size; ++ ++ /* Set the backplane window to include the start address */ ++ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); ++ if (bcmerror) { ++ brcmf_dbg(ERROR, "window change failed\n"); ++ goto xfer_done; ++ } ++ ++ /* Do the transfer(s) */ ++ while (size) { ++ brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n", ++ write ? "write" : "read", dsize, ++ sdaddr, address & SBSDIO_SBWINDOW_MASK); ++ bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write, ++ sdaddr, data, dsize); ++ if (bcmerror) { ++ brcmf_dbg(ERROR, "membytes transfer failed\n"); ++ break; ++ } ++ ++ /* Adjust for next transfer (if any) */ ++ size -= dsize; ++ if (size) { ++ data += dsize; ++ address += dsize; ++ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, ++ address); ++ if (bcmerror) { ++ brcmf_dbg(ERROR, "window change failed\n"); ++ break; ++ } ++ sdaddr = 0; ++ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); ++ } ++ } ++ ++xfer_done: ++ /* Return the window to backplane enumeration space for core access */ ++ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad)) ++ brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", ++ bus->sdiodev->sbwad); ++ ++ return bcmerror; ++} ++ ++#ifdef BCMDBG ++#define CONSOLE_LINE_MAX 192 ++ ++static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) ++{ ++ struct brcmf_console *c = &bus->console; ++ u8 line[CONSOLE_LINE_MAX], ch; ++ u32 n, idx, addr; ++ int rv; ++ ++ /* Don't do anything until FWREADY updates console address */ ++ if (bus->console_addr == 0) ++ return 0; ++ ++ /* Read console log struct */ ++ addr = bus->console_addr + offsetof(struct rte_console, log_le); ++ rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le, ++ sizeof(c->log_le)); ++ if (rv < 0) ++ return rv; ++ ++ /* Allocate console buffer (one time only) */ ++ if (c->buf == NULL) { ++ c->bufsize = le32_to_cpu(c->log_le.buf_size); ++ c->buf = kmalloc(c->bufsize, GFP_ATOMIC); ++ if (c->buf == NULL) ++ return -ENOMEM; ++ } ++ ++ idx = le32_to_cpu(c->log_le.idx); ++ ++ /* Protect against corrupt value */ ++ if (idx > c->bufsize) ++ return -EBADE; ++ ++ /* Skip reading the console buffer if the index pointer ++ has not moved */ ++ if (idx == c->last) ++ return 0; ++ ++ /* Read the console buffer */ ++ addr = le32_to_cpu(c->log_le.buf); ++ rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize); ++ if (rv < 0) ++ return rv; ++ ++ while (c->last != idx) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ if (c->last == idx) { ++ /* This would output a partial line. ++ * Instead, back up ++ * the buffer pointer and output this ++ * line next time around. ++ */ ++ if (c->last >= n) ++ c->last -= n; ++ else ++ c->last = c->bufsize - n; ++ goto break2; ++ } ++ ch = c->buf[c->last]; ++ c->last = (c->last + 1) % c->bufsize; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ printk(KERN_DEBUG "CONSOLE: %s\n", line); ++ } ++ } ++break2: ++ ++ return 0; ++} ++#endif /* BCMDBG */ ++ ++static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) ++{ ++ int i; ++ int ret; ++ ++ bus->ctrl_frame_stat = false; ++ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, ++ SDIO_FUNC_2, F2SYNC, frame, len, NULL); ++ ++ if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ++ ret); ++ bus->tx_sderrs++; ++ ++ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ u8 hi, lo; ++ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, ++ NULL); ++ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, ++ NULL); ++ bus->f1regdata += 2; ++ if (hi == 0 && lo == 0) ++ break; ++ } ++ return ret; ++ } ++ ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ ++ return ret; ++} ++ ++int ++brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) ++{ ++ u8 *frame; ++ u16 len; ++ u32 swheader; ++ uint retries = 0; ++ u8 doff = 0; ++ int ret = -1; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Back the pointer to make a room for bus header */ ++ frame = msg - SDPCM_HDRLEN; ++ len = (msglen += SDPCM_HDRLEN); ++ ++ /* Add alignment padding (optional for ctl frames) */ ++ doff = ((unsigned long)frame % BRCMF_SDALIGN); ++ if (doff) { ++ frame -= doff; ++ len += doff; ++ msglen += doff; ++ memset(frame, 0, doff + SDPCM_HDRLEN); ++ } ++ /* precondition: doff < BRCMF_SDALIGN */ ++ doff += SDPCM_HDRLEN; ++ ++ /* Round send length to next SDIO block */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ u16 pad = bus->blocksize - (len % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize)) ++ len += pad; ++ } else if (len % BRCMF_SDALIGN) { ++ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (len & (ALIGNMENT - 1)) ++ len = roundup(len, ALIGNMENT); ++ ++ /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ ++ ++ /* Need to lock here to protect txseq and SDIO tx calls */ ++ down(&bus->sdsem); ++ ++ bus_wake(bus); ++ ++ /* Make sure backplane clock is on */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ *(__le16 *) frame = cpu_to_le16((u16) msglen); ++ *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen); ++ ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ++ ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & ++ SDPCM_CHANNEL_MASK) ++ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & ++ SDPCM_DOFFSET_MASK); ++ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); ++ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ ++ if (!data_ok(bus)) { ++ brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", ++ bus->tx_max, bus->tx_seq); ++ bus->ctrl_frame_stat = true; ++ /* Send from dpc */ ++ bus->ctrl_frame_buf = frame; ++ bus->ctrl_frame_len = len; ++ ++ brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); ++ ++ if (bus->ctrl_frame_stat == false) { ++ brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); ++ ret = 0; ++ } else { ++ brcmf_dbg(INFO, "ctrl_frame_stat == true\n"); ++ ret = -1; ++ } ++ } ++ ++ if (ret == -1) { ++#ifdef BCMDBG ++ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { ++ printk(KERN_DEBUG "Tx Frame:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ frame, len); ++ } else if (BRCMF_HDRS_ON()) { ++ printk(KERN_DEBUG "TxHdr:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ frame, min_t(u16, len, 16)); ++ } ++#endif ++ ++ do { ++ ret = brcmf_tx_frame(bus, frame, len); ++ } while (ret < 0 && retries++ < TXRETRIES); ++ } ++ ++ if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = false; ++ brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); ++ } ++ ++ up(&bus->sdsem); ++ ++ if (ret) ++ bus->drvr->tx_ctlerrs++; ++ else ++ bus->drvr->tx_ctlpkts++; ++ ++ return ret ? -EIO : 0; ++} ++ ++int ++brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) ++{ ++ int timeleft; ++ uint rxlen = 0; ++ bool pending; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Wait until control frame is available */ ++ timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); ++ ++ down(&bus->sdsem); ++ rxlen = bus->rxlen; ++ memcpy(msg, bus->rxctl, min(msglen, rxlen)); ++ bus->rxlen = 0; ++ up(&bus->sdsem); ++ ++ if (rxlen) { ++ brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", ++ rxlen, msglen); ++ } else if (timeleft == 0) { ++ brcmf_dbg(ERROR, "resumed on timeout\n"); ++ } else if (pending == true) { ++ brcmf_dbg(CTL, "cancelled\n"); ++ return -ERESTARTSYS; ++ } else { ++ brcmf_dbg(CTL, "resumed for unknown reason?\n"); ++ } ++ ++ if (rxlen) ++ bus->drvr->rx_ctlpkts++; ++ else ++ bus->drvr->rx_ctlerrs++; ++ ++ return rxlen ? (int)rxlen : -ETIMEDOUT; ++} ++ ++static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) ++{ ++ int bcmerror = 0; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Basic sanity checks */ ++ if (bus->drvr->up) { ++ bcmerror = -EISCONN; ++ goto err; ++ } ++ if (!len) { ++ bcmerror = -EOVERFLOW; ++ goto err; ++ } ++ ++ /* Free the old ones and replace with passed variables */ ++ kfree(bus->vars); ++ ++ bus->vars = kmalloc(len, GFP_ATOMIC); ++ bus->varsz = bus->vars ? len : 0; ++ if (bus->vars == NULL) { ++ bcmerror = -ENOMEM; ++ goto err; ++ } ++ ++ /* Copy the passed variables, which should include the ++ terminating double-null */ ++ memcpy(bus->vars, arg, bus->varsz); ++err: ++ return bcmerror; ++} ++ ++static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) ++{ ++ int bcmerror = 0; ++ u32 varsize; ++ u32 varaddr; ++ u8 *vbuffer; ++ u32 varsizew; ++ __le32 varsizew_le; ++#ifdef BCMDBG ++ char *nvram_ularray; ++#endif /* BCMDBG */ ++ ++ /* Even if there are no vars are to be written, we still ++ need to set the ramsize. */ ++ varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; ++ varaddr = (bus->ramsize - 4) - varsize; ++ ++ if (bus->vars) { ++ vbuffer = kzalloc(varsize, GFP_ATOMIC); ++ if (!vbuffer) ++ return -ENOMEM; ++ ++ memcpy(vbuffer, bus->vars, bus->varsz); ++ ++ /* Write the vars list */ ++ bcmerror = ++ brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); ++#ifdef BCMDBG ++ /* Verify NVRAM bytes */ ++ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); ++ nvram_ularray = kmalloc(varsize, GFP_ATOMIC); ++ if (!nvram_ularray) ++ return -ENOMEM; ++ ++ /* Upload image to verify downloaded contents. */ ++ memset(nvram_ularray, 0xaa, varsize); ++ ++ /* Read the vars list to temp buffer for comparison */ ++ bcmerror = ++ brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, ++ varsize); ++ if (bcmerror) { ++ brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", ++ bcmerror, varsize, varaddr); ++ } ++ /* Compare the org NVRAM with the one read from RAM */ ++ if (memcmp(vbuffer, nvram_ularray, varsize)) ++ brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); ++ else ++ brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); ++ ++ kfree(nvram_ularray); ++#endif /* BCMDBG */ ++ ++ kfree(vbuffer); ++ } ++ ++ /* adjust to the user specified RAM */ ++ brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); ++ brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", ++ varaddr, varsize); ++ varsize = ((bus->ramsize - 4) - varaddr); ++ ++ /* ++ * Determine the length token: ++ * Varsize, converted to words, in lower 16-bits, checksum ++ * in upper 16-bits. ++ */ ++ if (bcmerror) { ++ varsizew = 0; ++ varsizew_le = cpu_to_le32(0); ++ } else { ++ varsizew = varsize / 4; ++ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); ++ varsizew_le = cpu_to_le32(varsizew); ++ } ++ ++ brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", ++ varsize, varsizew); ++ ++ /* Write the length token to the last word */ ++ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), ++ (u8 *)&varsizew_le, 4); ++ ++ return bcmerror; ++} ++ ++static void ++brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase) ++{ ++ u32 regdata; ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4); ++ if (regdata & SBTML_RESET) ++ return; ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4); ++ if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) { ++ /* ++ * set target reject and spin until busy is clear ++ * (preserve core-specific bits) ++ */ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4); ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), ++ 4, regdata | SBTML_REJ); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4); ++ udelay(1); ++ SPINWAIT((brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatehigh), 4) & ++ SBTMH_BUSY), 100000); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatehigh), 4); ++ if (regdata & SBTMH_BUSY) ++ brcmf_dbg(ERROR, "ARM core still busy\n"); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbidlow), 4); ++ if (regdata & SBIDL_INIT) { ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbimstate), 4) | ++ SBIM_RJ; ++ brcmf_sdcard_reg_write(sdiodev, ++ CORE_SB(corebase, sbimstate), 4, ++ regdata); ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbimstate), 4); ++ udelay(1); ++ SPINWAIT((brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbimstate), 4) & ++ SBIM_BY), 100000); ++ } ++ ++ /* set reset and reject while enabling the clocks */ ++ brcmf_sdcard_reg_write(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4, ++ (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_REJ | SBTML_RESET)); ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatelow), 4); ++ udelay(10); ++ ++ /* clear the initiator reject bit */ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbidlow), 4); ++ if (regdata & SBIDL_INIT) { ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbimstate), 4) & ++ ~SBIM_RJ; ++ brcmf_sdcard_reg_write(sdiodev, ++ CORE_SB(corebase, sbimstate), 4, ++ regdata); ++ } ++ } ++ ++ /* leave reset and reject asserted */ ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, ++ (SBTML_REJ | SBTML_RESET)); ++ udelay(1); ++} ++ ++static void ++brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase) ++{ ++ u32 regdata; ++ ++ /* ++ * Must do the disable sequence first to work for ++ * arbitrary current core state. ++ */ ++ brcmf_sdbrcm_chip_disablecore(sdiodev, corebase); ++ ++ /* ++ * Now do the initialization sequence. ++ * set reset while enabling the clock and ++ * forcing them on throughout the core ++ */ ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, ++ ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_RESET); ++ udelay(1); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbtmstatehigh), 4); ++ if (regdata & SBTMH_SERR) ++ brcmf_sdcard_reg_write(sdiodev, ++ CORE_SB(corebase, sbtmstatehigh), 4, 0); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(corebase, sbimstate), 4); ++ if (regdata & (SBIM_IBE | SBIM_TO)) ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4, ++ regdata & ~(SBIM_IBE | SBIM_TO)); ++ ++ /* clear reset and allow it to propagate throughout the core */ ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, ++ (SICF_FGC << SBTML_SICF_SHIFT) | ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++ udelay(1); ++ ++ /* leave clock enabled */ ++ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++ udelay(1); ++} ++ ++static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) ++{ ++ uint retries; ++ u32 regdata; ++ int bcmerror = 0; ++ ++ /* To enter download state, disable ARM and reset SOCRAM. ++ * To exit download state, simply reset ARM (default is RAM boot). ++ */ ++ if (enter) { ++ bus->alp_only = true; ++ ++ brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ++ bus->ci->armcorebase); ++ ++ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase); ++ ++ /* Clear the top bit of memory */ ++ if (bus->ramsize) { ++ u32 zeros = 0; ++ brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4, ++ (u8 *)&zeros, 4); ++ } ++ } else { ++ regdata = brcmf_sdcard_reg_read(bus->sdiodev, ++ CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4); ++ regdata &= (SBTML_RESET | SBTML_REJ_MASK | ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++ if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) { ++ brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); ++ bcmerror = -EBADE; ++ goto fail; ++ } ++ ++ bcmerror = brcmf_sdbrcm_write_vars(bus); ++ if (bcmerror) { ++ brcmf_dbg(ERROR, "no vars written to RAM\n"); ++ bcmerror = 0; ++ } ++ ++ w_sdreg32(bus, 0xFFFFFFFF, ++ offsetof(struct sdpcmd_regs, intstatus), &retries); ++ ++ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase); ++ ++ /* Allow HT Clock now that the ARM is running. */ ++ bus->alp_only = false; ++ ++ bus->drvr->busstate = BRCMF_BUS_LOAD; ++ } ++fail: ++ return bcmerror; ++} ++ ++static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) ++{ ++ if (bus->firmware->size < bus->fw_ptr + len) ++ len = bus->firmware->size - bus->fw_ptr; ++ ++ memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); ++ bus->fw_ptr += len; ++ return len; ++} ++ ++MODULE_FIRMWARE(BCM4329_FW_NAME); ++MODULE_FIRMWARE(BCM4329_NV_NAME); ++ ++static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) ++{ ++ int offset = 0; ++ uint len; ++ u8 *memblock = NULL, *memptr; ++ int ret; ++ ++ brcmf_dbg(INFO, "Enter\n"); ++ ++ bus->fw_name = BCM4329_FW_NAME; ++ ret = request_firmware(&bus->firmware, bus->fw_name, ++ &bus->sdiodev->func[2]->dev); ++ if (ret) { ++ brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); ++ return ret; ++ } ++ bus->fw_ptr = 0; ++ ++ memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); ++ if (memblock == NULL) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) ++ memptr += (BRCMF_SDALIGN - ++ ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); ++ ++ /* Download image */ ++ while ((len = ++ brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) { ++ ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len); ++ if (ret) { ++ brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n", ++ ret, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++err: ++ kfree(memblock); ++ ++ release_firmware(bus->firmware); ++ bus->fw_ptr = 0; ++ ++ return ret; ++} ++ ++/* ++ * ProcessVars:Takes a buffer of "=\n" lines read from a file ++ * and ending in a NUL. ++ * Removes carriage returns, empty lines, comment lines, and converts ++ * newlines to NULs. ++ * Shortens buffer as needed and pads with NULs. End of buffer is marked ++ * by two NULs. ++*/ ++ ++static uint brcmf_process_nvram_vars(char *varbuf, uint len) ++{ ++ char *dp; ++ bool findNewline; ++ int column; ++ uint buf_len, n; ++ ++ dp = varbuf; ++ ++ findNewline = false; ++ column = 0; ++ ++ for (n = 0; n < len; n++) { ++ if (varbuf[n] == 0) ++ break; ++ if (varbuf[n] == '\r') ++ continue; ++ if (findNewline && varbuf[n] != '\n') ++ continue; ++ findNewline = false; ++ if (varbuf[n] == '#') { ++ findNewline = true; ++ continue; ++ } ++ if (varbuf[n] == '\n') { ++ if (column == 0) ++ continue; ++ *dp++ = 0; ++ column = 0; ++ continue; ++ } ++ *dp++ = varbuf[n]; ++ column++; ++ } ++ buf_len = dp - varbuf; ++ ++ while (dp < varbuf + n) ++ *dp++ = 0; ++ ++ return buf_len; ++} ++ ++static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) ++{ ++ uint len; ++ char *memblock = NULL; ++ char *bufp; ++ int ret; ++ ++ bus->nv_name = BCM4329_NV_NAME; ++ ret = request_firmware(&bus->firmware, bus->nv_name, ++ &bus->sdiodev->func[2]->dev); ++ if (ret) { ++ brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); ++ return ret; ++ } ++ bus->fw_ptr = 0; ++ ++ memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); ++ if (memblock == NULL) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); ++ ++ if (len > 0 && len < MEMBLOCK) { ++ bufp = (char *)memblock; ++ bufp[len] = 0; ++ len = brcmf_process_nvram_vars(bufp, len); ++ bufp += len; ++ *bufp++ = 0; ++ if (len) ++ ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); ++ if (ret) ++ brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); ++ } else { ++ brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); ++ ret = -EIO; ++ } ++ ++err: ++ kfree(memblock); ++ ++ release_firmware(bus->firmware); ++ bus->fw_ptr = 0; ++ ++ return ret; ++} ++ ++static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) ++{ ++ int bcmerror = -1; ++ ++ /* Keep arm in reset */ ++ if (brcmf_sdbrcm_download_state(bus, true)) { ++ brcmf_dbg(ERROR, "error placing ARM core in reset\n"); ++ goto err; ++ } ++ ++ /* External image takes precedence if specified */ ++ if (brcmf_sdbrcm_download_code_file(bus)) { ++ brcmf_dbg(ERROR, "dongle image file download failed\n"); ++ goto err; ++ } ++ ++ /* External nvram takes precedence if specified */ ++ if (brcmf_sdbrcm_download_nvram(bus)) ++ brcmf_dbg(ERROR, "dongle nvram file download failed\n"); ++ ++ /* Take arm out of reset */ ++ if (brcmf_sdbrcm_download_state(bus, false)) { ++ brcmf_dbg(ERROR, "error getting out of ARM core reset\n"); ++ goto err; ++ } ++ ++ bcmerror = 0; ++ ++err: ++ return bcmerror; ++} ++ ++static bool ++brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) ++{ ++ bool ret; ++ ++ /* Download the firmware */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ ++ ret = _brcmf_sdbrcm_download_firmware(bus) == 0; ++ ++ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); ++ ++ return ret; ++} ++ ++void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) ++{ ++ u32 local_hostintmask; ++ u8 saveclk; ++ uint retries; ++ int err; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (bus->watchdog_tsk) { ++ send_sig(SIGTERM, bus->watchdog_tsk, 1); ++ kthread_stop(bus->watchdog_tsk); ++ bus->watchdog_tsk = NULL; ++ } ++ ++ if (bus->dpc_tsk && bus->dpc_tsk != current) { ++ send_sig(SIGTERM, bus->dpc_tsk, 1); ++ kthread_stop(bus->dpc_tsk); ++ bus->dpc_tsk = NULL; ++ } ++ ++ down(&bus->sdsem); ++ ++ bus_wake(bus); ++ ++ /* Enable clock for device interrupts */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ ++ /* Disable and clear interrupts at the chip level also */ ++ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); ++ local_hostintmask = bus->hostintmask; ++ bus->hostintmask = 0; ++ ++ /* Change our idea of bus state */ ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) ++ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); ++ ++ /* Turn off the bus (F2), free any pending packets */ ++ brcmf_dbg(INTR, "disable SDIO interrupts\n"); ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, ++ SDIO_FUNC_ENABLE_1, NULL); ++ ++ /* Clear any pending interrupts now that F2 is disabled */ ++ w_sdreg32(bus, local_hostintmask, ++ offsetof(struct sdpcmd_regs, intstatus), &retries); ++ ++ /* Turn off the backplane clock (only) */ ++ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); ++ ++ /* Clear the data packet queues */ ++ brcmu_pktq_flush(&bus->txq, true, NULL, NULL); ++ ++ /* Clear any held glomming stuff */ ++ if (bus->glomd) ++ brcmu_pkt_buf_free_skb(bus->glomd); ++ ++ if (bus->glom) ++ brcmu_pkt_buf_free_skb(bus->glom); ++ ++ bus->glom = bus->glomd = NULL; ++ ++ /* Clear rx control and wake any waiters */ ++ bus->rxlen = 0; ++ brcmf_sdbrcm_dcmd_resp_wake(bus); ++ ++ /* Reset some F2 state stuff */ ++ bus->rxskip = false; ++ bus->tx_seq = bus->rx_seq = 0; ++ ++ up(&bus->sdsem); ++} ++ ++int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) ++{ ++ struct brcmf_bus *bus = drvr->bus; ++ unsigned long timeout; ++ uint retries = 0; ++ u8 ready, enable; ++ int err, ret = 0; ++ u8 saveclk; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* try to download image and nvram to the dongle */ ++ if (drvr->busstate == BRCMF_BUS_DOWN) { ++ if (!(brcmf_sdbrcm_download_firmware(bus))) ++ return -1; ++ } ++ ++ if (!bus->drvr) ++ return 0; ++ ++ /* Start the watchdog timer */ ++ bus->drvr->tickcnt = 0; ++ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); ++ ++ down(&bus->sdsem); ++ ++ /* Make sure backplane clock is on, needed to generate F2 interrupt */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ if (bus->clkstate != CLK_AVAIL) ++ goto exit; ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = ++ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); ++ goto exit; ++ } ++ ++ /* Enable function 2 (frame transfers) */ ++ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, ++ offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); ++ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, ++ enable, NULL); ++ ++ timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); ++ ready = 0; ++ while (enable != ready) { ++ ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0, ++ SDIO_CCCR_IORx, NULL); ++ if (time_after(jiffies, timeout)) ++ break; ++ else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) ++ /* prevent busy waiting if it takes too long */ ++ msleep_interruptible(20); ++ } ++ ++ brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready); ++ ++ /* If F2 successfully enabled, set core and enable interrupts */ ++ if (ready == enable) { ++ /* Set up the interrupt mask and enable interrupts */ ++ bus->hostintmask = HOSTINTMASK; ++ w_sdreg32(bus, bus->hostintmask, ++ offsetof(struct sdpcmd_regs, hostintmask), &retries); ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_WATERMARK, 8, &err); ++ ++ /* Set bus state according to enable result */ ++ drvr->busstate = BRCMF_BUS_DATA; ++ } ++ ++ else { ++ /* Disable F2 again */ ++ enable = SDIO_FUNC_ENABLE_1; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, ++ SDIO_CCCR_IOEx, enable, NULL); ++ } ++ ++ /* Restore previous clock setting */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); ++ ++ /* If we didn't come up, turn off backplane clock */ ++ if (drvr->busstate != BRCMF_BUS_DATA) ++ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); ++ ++exit: ++ up(&bus->sdsem); ++ ++ return ret; ++} ++ ++void brcmf_sdbrcm_isr(void *arg) ++{ ++ struct brcmf_bus *bus = (struct brcmf_bus *) arg; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (!bus) { ++ brcmf_dbg(ERROR, "bus is null pointer, exiting\n"); ++ return; ++ } ++ ++ if (bus->drvr->busstate == BRCMF_BUS_DOWN) { ++ brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); ++ return; ++ } ++ /* Count the interrupt call */ ++ bus->intrcount++; ++ bus->ipend = true; ++ ++ /* Shouldn't get this interrupt if we're sleeping? */ ++ if (bus->sleeping) { ++ brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); ++ return; ++ } ++ ++ /* Disable additional interrupts (is this needed now)? */ ++ if (!bus->intr) ++ brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); ++ ++ bus->dpc_sched = true; ++ if (bus->dpc_tsk) ++ complete(&bus->dpc_wait); ++} ++ ++static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) ++{ ++ struct brcmf_bus *bus; ++ ++ brcmf_dbg(TIMER, "Enter\n"); ++ ++ bus = drvr->bus; ++ ++ /* Ignore the timer if simulating bus down */ ++ if (bus->sleeping) ++ return false; ++ ++ down(&bus->sdsem); ++ ++ /* Poll period: check device if appropriate. */ ++ if (bus->poll && (++bus->polltick >= bus->pollrate)) { ++ u32 intstatus = 0; ++ ++ /* Reset poll tick */ ++ bus->polltick = 0; ++ ++ /* Check device if no interrupts */ ++ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { ++ ++ if (!bus->dpc_sched) { ++ u8 devpend; ++ devpend = brcmf_sdcard_cfg_read(bus->sdiodev, ++ SDIO_FUNC_0, SDIO_CCCR_INTx, ++ NULL); ++ intstatus = ++ devpend & (INTR_STATUS_FUNC1 | ++ INTR_STATUS_FUNC2); ++ } ++ ++ /* If there is something, make like the ISR and ++ schedule the DPC */ ++ if (intstatus) { ++ bus->pollcnt++; ++ bus->ipend = true; ++ ++ bus->dpc_sched = true; ++ if (bus->dpc_tsk) ++ complete(&bus->dpc_wait); ++ } ++ } ++ ++ /* Update interrupt tracking */ ++ bus->lastintrs = bus->intrcount; ++ } ++#ifdef BCMDBG ++ /* Poll for console output periodically */ ++ if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { ++ bus->console.count += BRCMF_WD_POLL_MS; ++ if (bus->console.count >= bus->console_interval) { ++ bus->console.count -= bus->console_interval; ++ /* Make sure backplane clock is on */ ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ if (brcmf_sdbrcm_readconsole(bus) < 0) ++ /* stop on error */ ++ bus->console_interval = 0; ++ } ++ } ++#endif /* BCMDBG */ ++ ++ /* On idle timeout clear activity flag and/or turn off clock */ ++ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { ++ if (++bus->idlecount >= bus->idletime) { ++ bus->idlecount = 0; ++ if (bus->activity) { ++ bus->activity = false; ++ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); ++ } else { ++ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); ++ } ++ } ++ } ++ ++ up(&bus->sdsem); ++ ++ return bus->ipend; ++} ++ ++static bool brcmf_sdbrcm_chipmatch(u16 chipid) ++{ ++ if (chipid == BCM4329_CHIP_ID) ++ return true; ++ return false; ++} ++ ++static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ kfree(bus->rxbuf); ++ bus->rxctl = bus->rxbuf = NULL; ++ bus->rxlen = 0; ++ ++ kfree(bus->databuf); ++ bus->databuf = NULL; ++} ++ ++static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (bus->drvr->maxctl) { ++ bus->rxblen = ++ roundup((bus->drvr->maxctl + SDPCM_HDRLEN), ++ ALIGNMENT) + BRCMF_SDALIGN; ++ bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); ++ if (!(bus->rxbuf)) ++ goto fail; ++ } ++ ++ /* Allocate buffer to receive glomed packet */ ++ bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC); ++ if (!(bus->databuf)) { ++ /* release rxbuf which was already located as above */ ++ if (!bus->rxblen) ++ kfree(bus->rxbuf); ++ goto fail; ++ } ++ ++ /* Align the buffer */ ++ if ((unsigned long)bus->databuf % BRCMF_SDALIGN) ++ bus->dataptr = bus->databuf + (BRCMF_SDALIGN - ++ ((unsigned long)bus->databuf % BRCMF_SDALIGN)); ++ else ++ bus->dataptr = bus->databuf; ++ ++ return true; ++ ++fail: ++ return false; ++} ++ ++/* SDIO Pad drive strength to select value mappings */ ++struct sdiod_drive_str { ++ u8 strength; /* Pad Drive Strength in mA */ ++ u8 sel; /* Chip-specific select value */ ++}; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 1 */ ++static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { ++ { ++ 4, 0x2}, { ++ 2, 0x3}, { ++ 1, 0x0}, { ++ 0, 0x0} ++ }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ ++static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { ++ { ++ 12, 0x7}, { ++ 10, 0x6}, { ++ 8, 0x5}, { ++ 6, 0x4}, { ++ 4, 0x2}, { ++ 2, 0x1}, { ++ 0, 0x0} ++ }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ ++static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { ++ { ++ 32, 0x7}, { ++ 26, 0x6}, { ++ 22, 0x5}, { ++ 16, 0x4}, { ++ 12, 0x3}, { ++ 8, 0x2}, { ++ 4, 0x1}, { ++ 0, 0x0} ++ }; ++ ++#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) ++ ++static char *brcmf_chipname(uint chipid, char *buf, uint len) ++{ ++ const char *fmt; ++ ++ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; ++ snprintf(buf, len, fmt, chipid); ++ return buf; ++} ++ ++static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, ++ u32 drivestrength) { ++ struct sdiod_drive_str *str_tab = NULL; ++ u32 str_mask = 0; ++ u32 str_shift = 0; ++ char chn[8]; ++ ++ if (!(bus->ci->cccaps & CC_CAP_PMU)) ++ return; ++ ++ switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) { ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): ++ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; ++ str_mask = 0x30000000; ++ str_shift = 28; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): ++ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): ++ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ default: ++ brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", ++ brcmf_chipname(bus->ci->chip, chn, 8), ++ bus->ci->chiprev, bus->ci->pmurev); ++ break; ++ } ++ ++ if (str_tab != NULL) { ++ u32 drivestrength_sel = 0; ++ u32 cc_data_temp; ++ int i; ++ ++ for (i = 0; str_tab[i].strength != 0; i++) { ++ if (drivestrength >= str_tab[i].strength) { ++ drivestrength_sel = str_tab[i].sel; ++ break; ++ } ++ } ++ ++ brcmf_sdcard_reg_write(bus->sdiodev, ++ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), ++ 4, 1); ++ cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev, ++ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4); ++ cc_data_temp &= ~str_mask; ++ drivestrength_sel <<= str_shift; ++ cc_data_temp |= drivestrength_sel; ++ brcmf_sdcard_reg_write(bus->sdiodev, ++ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), ++ 4, cc_data_temp); ++ ++ brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n", ++ drivestrength, cc_data_temp); ++ } ++} ++ ++static int ++brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev, ++ struct chip_info *ci, u32 regs) ++{ ++ u32 regdata; ++ ++ /* ++ * Get CC core rev ++ * Chipid is assume to be at offset 0 from regs arg ++ * For different chiptypes or old sdio hosts w/o chipcommon, ++ * other ways of recognition should be added here. ++ */ ++ ci->cccorebase = regs; ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_CC_REG(ci->cccorebase, chipid), 4); ++ ci->chip = regdata & CID_ID_MASK; ++ ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; ++ ++ brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); ++ ++ /* Address of cores for new chips should be added here */ ++ switch (ci->chip) { ++ case BCM4329_CHIP_ID: ++ ci->buscorebase = BCM4329_CORE_BUS_BASE; ++ ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE; ++ ci->armcorebase = BCM4329_CORE_ARM_BASE; ++ ci->ramsize = BCM4329_RAMSIZE; ++ break; ++ default: ++ brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); ++ return -ENODEV; ++ } ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(ci->cccorebase, sbidhigh), 4); ++ ci->ccrev = SBCOREREV(regdata); ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_CC_REG(ci->cccorebase, pmucapabilities), 4); ++ ci->pmurev = regdata & PCAP_REV_MASK; ++ ++ regdata = brcmf_sdcard_reg_read(sdiodev, ++ CORE_SB(ci->buscorebase, sbidhigh), 4); ++ ci->buscorerev = SBCOREREV(regdata); ++ ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT; ++ ++ brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", ++ ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype); ++ ++ /* get chipcommon capabilites */ ++ ci->cccaps = brcmf_sdcard_reg_read(sdiodev, ++ CORE_CC_REG(ci->cccorebase, capabilities), 4); ++ ++ return 0; ++} ++ ++static int ++brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs) ++{ ++ struct chip_info *ci; ++ int err; ++ u8 clkval, clkset; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* alloc chip_info_t */ ++ ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC); ++ if (NULL == ci) ++ return -ENOMEM; ++ ++ /* bus/core/clk setup for register access */ ++ /* Try forcing SDIO core to do ALPAvail request only */ ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); ++ if (err) { ++ brcmf_dbg(ERROR, "error writing for HT off\n"); ++ goto fail; ++ } ++ ++ /* If register supported, wait for ALPAvail and then force ALP */ ++ /* This may take up to 15 milliseconds */ ++ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL); ++ if ((clkval & ~SBSDIO_AVBITS) == clkset) { ++ SPINWAIT(((clkval = ++ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ NULL)), ++ !SBSDIO_ALPAV(clkval)), ++ PMU_MAX_TRANSITION_DLY); ++ if (!SBSDIO_ALPAV(clkval)) { ++ brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n", ++ clkval); ++ err = -EBUSY; ++ goto fail; ++ } ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | ++ SBSDIO_FORCE_ALP; ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ clkset, &err); ++ udelay(65); ++ } else { ++ brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", ++ clkset, clkval); ++ err = -EACCES; ++ goto fail; ++ } ++ ++ /* Also, disable the extra SDIO pull-ups */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); ++ ++ err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs); ++ if (err) ++ goto fail; ++ ++ /* ++ * Make sure any on-chip ARM is off (in case strapping is wrong), ++ * or downloaded code was already running. ++ */ ++ brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase); ++ ++ brcmf_sdcard_reg_write(bus->sdiodev, ++ CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0); ++ brcmf_sdcard_reg_write(bus->sdiodev, ++ CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0); ++ ++ /* Disable F2 to clear any intermediate frame state on the dongle */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, ++ SDIO_FUNC_ENABLE_1, NULL); ++ ++ /* WAR: cmd52 backplane read so core HW will drop ALPReq */ ++ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ 0, NULL); ++ ++ /* Done with backplane-dependent accesses, can drop clock... */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ bus->ci = ci; ++ return 0; ++fail: ++ bus->ci = NULL; ++ kfree(ci); ++ return err; ++} ++ ++static bool ++brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva) ++{ ++ u8 clkctl = 0; ++ int err = 0; ++ int reg_addr; ++ u32 reg_val; ++ ++ bus->alp_only = true; ++ ++ /* Return the window to backplane enumeration space for core access */ ++ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) ++ brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); ++ ++#ifdef BCMDBG ++ printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n", ++ brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); ++ ++#endif /* BCMDBG */ ++ ++ /* ++ * Force PLL off until brcmf_sdbrcm_chip_attach() ++ * programs PLL control regs ++ */ ++ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, ++ BRCMF_INIT_CLKCTL1, &err); ++ if (!err) ++ clkctl = ++ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ ++ if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { ++ brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", ++ err, BRCMF_INIT_CLKCTL1, clkctl); ++ goto fail; ++ } ++ ++ if (brcmf_sdbrcm_chip_attach(bus, regsva)) { ++ brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n"); ++ goto fail; ++ } ++ ++ if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { ++ brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip); ++ goto fail; ++ } ++ ++ brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH); ++ ++ /* Get info on the ARM and SOCRAM cores... */ ++ brcmf_sdcard_reg_read(bus->sdiodev, ++ CORE_SB(bus->ci->armcorebase, sbidhigh), 4); ++ bus->ramsize = bus->ci->ramsize; ++ if (!(bus->ramsize)) { ++ brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n"); ++ goto fail; ++ } ++ ++ /* Set core control so an SDIO reset does a backplane reset */ ++ reg_addr = bus->ci->buscorebase + ++ offsetof(struct sdpcmd_regs, corecontrol); ++ reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32)); ++ brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32), ++ reg_val | CC_BPRESEN); ++ ++ brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); ++ ++ /* Locate an appropriately-aligned portion of hdrbuf */ ++ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], ++ BRCMF_SDALIGN); ++ ++ /* Set the poll and/or interrupt flags */ ++ bus->intr = true; ++ bus->poll = false; ++ if (bus->poll) ++ bus->pollrate = 1; ++ ++ return true; ++ ++fail: ++ return false; ++} ++ ++static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* Disable F2 to clear any intermediate frame state on the dongle */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, ++ SDIO_FUNC_ENABLE_1, NULL); ++ ++ bus->drvr->busstate = BRCMF_BUS_DOWN; ++ bus->sleeping = false; ++ bus->rxflow = false; ++ ++ /* Done with backplane-dependent accesses, can drop clock... */ ++ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ /* ...and initialize clock/power states */ ++ bus->clkstate = CLK_SDONLY; ++ bus->idletime = BRCMF_IDLE_INTERVAL; ++ bus->idleclock = BRCMF_IDLE_ACTIVE; ++ ++ /* Query the F2 block size, set roundup accordingly */ ++ bus->blocksize = bus->sdiodev->func[2]->cur_blksize; ++ bus->roundup = min(max_roundup, bus->blocksize); ++ ++ /* bus module does not support packet chaining */ ++ bus->use_rxchain = false; ++ bus->sd_rxchain = false; ++ ++ return true; ++} ++ ++static int ++brcmf_sdbrcm_watchdog_thread(void *data) ++{ ++ struct brcmf_bus *bus = (struct brcmf_bus *)data; ++ ++ allow_signal(SIGTERM); ++ /* Run until signal received */ ++ while (1) { ++ if (kthread_should_stop()) ++ break; ++ if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { ++ brcmf_sdbrcm_bus_watchdog(bus->drvr); ++ /* Count the tick for reference */ ++ bus->drvr->tickcnt++; ++ } else ++ break; ++ } ++ return 0; ++} ++ ++static void ++brcmf_sdbrcm_watchdog(unsigned long data) ++{ ++ struct brcmf_bus *bus = (struct brcmf_bus *)data; ++ ++ if (bus->watchdog_tsk) { ++ complete(&bus->watchdog_wait); ++ /* Reschedule the watchdog */ ++ if (bus->wd_timer_valid) ++ mod_timer(&bus->timer, ++ jiffies + BRCMF_WD_POLL_MS * HZ / 1000); ++ } ++} ++ ++static void ++brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ kfree(bus->ci); ++ bus->ci = NULL; ++} ++ ++static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (bus->ci) { ++ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ++ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); ++ brcmf_sdbrcm_chip_detach(bus); ++ if (bus->vars && bus->varsz) ++ kfree(bus->vars); ++ bus->vars = NULL; ++ } ++ ++ brcmf_dbg(TRACE, "Disconnected\n"); ++} ++ ++/* Detach and free everything */ ++static void brcmf_sdbrcm_release(struct brcmf_bus *bus) ++{ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (bus) { ++ /* De-register interrupt handler */ ++ brcmf_sdcard_intr_dereg(bus->sdiodev); ++ ++ if (bus->drvr) { ++ brcmf_detach(bus->drvr); ++ brcmf_sdbrcm_release_dongle(bus); ++ bus->drvr = NULL; ++ } ++ ++ brcmf_sdbrcm_release_malloc(bus); ++ ++ kfree(bus); ++ } ++ ++ brcmf_dbg(TRACE, "Disconnected\n"); ++} ++ ++void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, ++ u32 regsva, struct brcmf_sdio_dev *sdiodev) ++{ ++ int ret; ++ struct brcmf_bus *bus; ++ ++ /* Init global variables at run-time, not as part of the declaration. ++ * This is required to support init/de-init of the driver. ++ * Initialization ++ * of globals as part of the declaration results in non-deterministic ++ * behavior since the value of the globals may be different on the ++ * first time that the driver is initialized vs subsequent ++ * initializations. ++ */ ++ brcmf_c_init(); ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ /* We make an assumption about address window mappings: ++ * regsva == SI_ENUM_BASE*/ ++ ++ /* Allocate private bus interface state */ ++ bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); ++ if (!bus) ++ goto fail; ++ ++ bus->sdiodev = sdiodev; ++ sdiodev->bus = bus; ++ bus->txbound = BRCMF_TXBOUND; ++ bus->rxbound = BRCMF_RXBOUND; ++ bus->txminmax = BRCMF_TXMINMAX; ++ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; ++ bus->usebufpool = false; /* Use bufpool if allocated, ++ else use locally malloced rxbuf */ ++ ++ /* attempt to attach to the dongle */ ++ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { ++ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); ++ goto fail; ++ } ++ ++ spin_lock_init(&bus->txqlock); ++ init_waitqueue_head(&bus->ctrl_wait); ++ init_waitqueue_head(&bus->dcmd_resp_wait); ++ ++ /* Set up the watchdog timer */ ++ init_timer(&bus->timer); ++ bus->timer.data = (unsigned long)bus; ++ bus->timer.function = brcmf_sdbrcm_watchdog; ++ ++ /* Initialize thread based operation and lock */ ++ sema_init(&bus->sdsem, 1); ++ ++ /* Initialize watchdog thread */ ++ init_completion(&bus->watchdog_wait); ++ bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, ++ bus, "brcmf_watchdog"); ++ if (IS_ERR(bus->watchdog_tsk)) { ++ printk(KERN_WARNING ++ "brcmf_watchdog thread failed to start\n"); ++ bus->watchdog_tsk = NULL; ++ } ++ /* Initialize DPC thread */ ++ init_completion(&bus->dpc_wait); ++ bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, ++ bus, "brcmf_dpc"); ++ if (IS_ERR(bus->dpc_tsk)) { ++ printk(KERN_WARNING ++ "brcmf_dpc thread failed to start\n"); ++ bus->dpc_tsk = NULL; ++ } ++ ++ /* Attach to the brcmf/OS/network interface */ ++ bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); ++ if (!bus->drvr) { ++ brcmf_dbg(ERROR, "brcmf_attach failed\n"); ++ goto fail; ++ } ++ ++ /* Allocate buffers */ ++ if (!(brcmf_sdbrcm_probe_malloc(bus))) { ++ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n"); ++ goto fail; ++ } ++ ++ if (!(brcmf_sdbrcm_probe_init(bus))) { ++ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n"); ++ goto fail; ++ } ++ ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n"); ++ ret = brcmf_sdcard_intr_reg(bus->sdiodev); ++ if (ret != 0) { ++ brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret); ++ goto fail; ++ } ++ brcmf_dbg(INTR, "registered SDIO interrupt function ok\n"); ++ ++ brcmf_dbg(INFO, "completed!!\n"); ++ ++ /* if firmware path present try to download and bring up bus */ ++ ret = brcmf_bus_start(bus->drvr); ++ if (ret != 0) { ++ if (ret == -ENOLINK) { ++ brcmf_dbg(ERROR, "dongle is not responding\n"); ++ goto fail; ++ } ++ } ++ /* Ok, have the per-port tell the stack we're open for business */ ++ if (brcmf_net_attach(bus->drvr, 0) != 0) { ++ brcmf_dbg(ERROR, "Net attach failed!!\n"); ++ goto fail; ++ } ++ ++ return bus; ++ ++fail: ++ brcmf_sdbrcm_release(bus); ++ return NULL; ++} ++ ++void brcmf_sdbrcm_disconnect(void *ptr) ++{ ++ struct brcmf_bus *bus = (struct brcmf_bus *)ptr; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (bus) ++ brcmf_sdbrcm_release(bus); ++ ++ brcmf_dbg(TRACE, "Disconnected\n"); ++} ++ ++struct device *brcmf_bus_get_device(struct brcmf_bus *bus) ++{ ++ return &bus->sdiodev->func[2]->dev; ++} ++ ++void ++brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) ++{ ++ /* don't start the wd until fw is loaded */ ++ if (bus->drvr->busstate == BRCMF_BUS_DOWN) ++ return; ++ ++ /* Totally stop the timer */ ++ if (!wdtick && bus->wd_timer_valid == true) { ++ del_timer_sync(&bus->timer); ++ bus->wd_timer_valid = false; ++ bus->save_ms = wdtick; ++ return; ++ } ++ ++ if (wdtick) { ++ if (bus->save_ms != BRCMF_WD_POLL_MS) { ++ if (bus->wd_timer_valid == true) ++ /* Stop timer and restart at new value */ ++ del_timer_sync(&bus->timer); ++ ++ /* Create timer again when watchdog period is ++ dynamically changed or in the first instance ++ */ ++ bus->timer.expires = ++ jiffies + BRCMF_WD_POLL_MS * HZ / 1000; ++ add_timer(&bus->timer); ++ ++ } else { ++ /* Re arm the timer, at last watchdog period */ ++ mod_timer(&bus->timer, ++ jiffies + BRCMF_WD_POLL_MS * HZ / 1000); ++ } ++ ++ bus->wd_timer_valid = true; ++ bus->save_ms = wdtick; ++ } ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/Makefile.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/Makefile +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/Makefile.orig 2011-11-09 13:46:58.235800758 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/Makefile 2011-11-09 13:47:16.986566342 -0500 +@@ -0,0 +1,33 @@ ++# ++# Makefile fragment for Broadcom 802.11n Networking Device Driver ++# ++# Copyright (c) 2010 Broadcom Corporation ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# 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. ++ ++ccflags-y += \ ++ -Idrivers/net/wireless/brcm80211/brcmfmac \ ++ -Idrivers/net/wireless/brcm80211/include ++ ++DHDOFILES = \ ++ wl_cfg80211.o \ ++ dhd_cdc.o \ ++ dhd_common.o \ ++ dhd_sdio.o \ ++ dhd_linux.o \ ++ bcmsdh.o \ ++ bcmsdh_sdmmc.o ++ ++obj-$(CONFIG_BRCMFMAC) += brcmfmac.o ++brcmfmac-objs += $(DHDOFILES) ++ccflags-y += -D__CHECK_ENDIAN__ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h.orig 2011-11-09 13:46:58.235800758 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h 2011-11-09 13:47:16.987566330 -0500 +@@ -0,0 +1,252 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_SDH_H_ ++#define _BRCM_SDH_H_ ++ ++#include ++ ++#define SDIO_FUNC_0 0 ++#define SDIO_FUNC_1 1 ++#define SDIO_FUNC_2 2 ++ ++#define SDIOD_FBR_SIZE 0x100 ++ ++/* io_en */ ++#define SDIO_FUNC_ENABLE_1 0x02 ++#define SDIO_FUNC_ENABLE_2 0x04 ++ ++/* io_rdys */ ++#define SDIO_FUNC_READY_1 0x02 ++#define SDIO_FUNC_READY_2 0x04 ++ ++/* intr_status */ ++#define INTR_STATUS_FUNC1 0x2 ++#define INTR_STATUS_FUNC2 0x4 ++ ++/* Maximum number of I/O funcs */ ++#define SDIOD_MAX_IOFUNCS 7 ++ ++/* as of sdiod rev 0, supports 3 functions */ ++#define SBSDIO_NUM_FUNCTION 3 ++ ++/* function 1 miscellaneous registers */ ++ ++/* sprom command and status */ ++#define SBSDIO_SPROM_CS 0x10000 ++/* sprom info register */ ++#define SBSDIO_SPROM_INFO 0x10001 ++/* sprom indirect access data byte 0 */ ++#define SBSDIO_SPROM_DATA_LOW 0x10002 ++/* sprom indirect access data byte 1 */ ++#define SBSDIO_SPROM_DATA_HIGH 0x10003 ++/* sprom indirect access addr byte 0 */ ++#define SBSDIO_SPROM_ADDR_LOW 0x10004 ++/* sprom indirect access addr byte 0 */ ++#define SBSDIO_SPROM_ADDR_HIGH 0x10005 ++/* xtal_pu (gpio) output */ ++#define SBSDIO_CHIP_CTRL_DATA 0x10006 ++/* xtal_pu (gpio) enable */ ++#define SBSDIO_CHIP_CTRL_EN 0x10007 ++/* rev < 7, watermark for sdio device */ ++#define SBSDIO_WATERMARK 0x10008 ++/* control busy signal generation */ ++#define SBSDIO_DEVICE_CTL 0x10009 ++ ++/* SB Address Window Low (b15) */ ++#define SBSDIO_FUNC1_SBADDRLOW 0x1000A ++/* SB Address Window Mid (b23:b16) */ ++#define SBSDIO_FUNC1_SBADDRMID 0x1000B ++/* SB Address Window High (b31:b24) */ ++#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C ++/* Frame Control (frame term/abort) */ ++#define SBSDIO_FUNC1_FRAMECTRL 0x1000D ++/* ChipClockCSR (ALP/HT ctl/status) */ ++#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E ++/* SdioPullUp (on cmd, d0-d2) */ ++#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F ++/* Write Frame Byte Count Low */ ++#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 ++/* Write Frame Byte Count High */ ++#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A ++/* Read Frame Byte Count Low */ ++#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B ++/* Read Frame Byte Count High */ ++#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C ++ ++#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ ++#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ ++ ++/* function 1 OCP space */ ++ ++/* sb offset addr is <= 15 bits, 32k */ ++#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF ++#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 ++/* with b15, maps to 32-bit SB access */ ++#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 ++ ++/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ ++ ++#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ ++#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ ++#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ ++/* Address bits from SBADDR regs */ ++#define SBSDIO_SBWINDOW_MASK 0xffff8000 ++ ++#define SDIOH_READ 0 /* Read request */ ++#define SDIOH_WRITE 1 /* Write request */ ++ ++#define SDIOH_DATA_FIX 0 /* Fixed addressing */ ++#define SDIOH_DATA_INC 1 /* Incremental addressing */ ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++struct brcmf_sdreg { ++ int func; ++ int offset; ++ int value; ++}; ++ ++struct brcmf_sdio_dev { ++ struct sdio_func *func[SDIO_MAX_FUNCS]; ++ u8 num_funcs; /* Supported funcs on client */ ++ u32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ u32 sbwad; /* Save backplane window address */ ++ bool regfail; /* status of last reg_r/w call */ ++ void *bus; ++ atomic_t suspend; /* suspend flag */ ++ wait_queue_head_t request_byte_wait; ++ wait_queue_head_t request_word_wait; ++ wait_queue_head_t request_packet_wait; ++ wait_queue_head_t request_buffer_wait; ++ ++}; ++ ++/* Register/deregister device interrupt handler. */ ++extern int ++brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev); ++ ++extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev); ++ ++/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). ++ * fn: function number ++ * addr: unmodified SDIO-space address ++ * data: data byte to write ++ * err: pointer to error code (or NULL) ++ */ ++extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func, ++ u32 addr, int *err); ++extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func, ++ u32 addr, u8 data, int *err); ++ ++/* Synchronous access to device (client) core registers via CMD53 to F1. ++ * addr: backplane address (i.e. >= regsva from attach) ++ * size: register width in bytes (2 or 4) ++ * data: data for register write ++ */ ++extern u32 ++brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size); ++ ++extern u32 ++brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, ++ u32 data); ++ ++/* Indicate if last reg read/write failed */ ++extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev); ++ ++/* Buffer transfer to/from device (client) core via cmd53. ++ * fn: function number ++ * addr: backplane address (i.e. >= regsva from attach) ++ * flags: backplane width, address increment, sync/async ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * pkt: pointer to packet associated with buf (if any) ++ * complete: callback function for command completion (async only) ++ * handle: handle for completion callback (first arg in callback) ++ * Returns 0 or error code. ++ * NOTE: Async operation is not currently supported. ++ */ ++extern int ++brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, ++ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); ++extern int ++brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, ++ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); ++ ++/* Flags bits */ ++ ++/* Four-byte target (backplane) width (vs. two-byte) */ ++#define SDIO_REQ_4BYTE 0x1 ++/* Fixed address (FIFO) (vs. incrementing address) */ ++#define SDIO_REQ_FIXED 0x2 ++/* Async request (vs. sync request) */ ++#define SDIO_REQ_ASYNC 0x4 ++ ++/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). ++ * rw: read or write (0/1) ++ * addr: direct SDIO address ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * Returns 0 or error code. ++ */ ++extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, ++ u32 addr, u8 *buf, uint nbytes); ++ ++/* Issue an abort to the specified function */ ++extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn); ++ ++/* platform specific/high level functions */ ++extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); ++extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev); ++ ++extern int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, ++ u32 address); ++ ++/* attach, return handler on success, NULL if failed. ++ * The handler shall be provided by all subsequent calls. No local cache ++ * cfghdl points to the starting address of pci device mapped memory ++ */ ++extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev); ++extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev); ++ ++/* read or write one byte using cmd52 */ ++extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, ++ uint fnc, uint addr, u8 *byte); ++ ++/* read or write 2/4 bytes using cmd53 */ ++extern int ++brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, ++ uint rw, uint fnc, uint addr, ++ u32 *word, uint nbyte); ++ ++/* read or write any buffer using cmd53 */ ++extern int ++brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, ++ uint fix_inc, uint rw, uint fnc_num, ++ u32 addr, uint regwidth, ++ u32 buflen, u8 *buffer, struct sk_buff *pkt); ++ ++/* Watchdog timer interface for pm ops */ ++extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, ++ bool enable); ++ ++extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, ++ u32 regsva, struct brcmf_sdio_dev *sdiodev); ++extern void brcmf_sdbrcm_disconnect(void *ptr); ++extern void brcmf_sdbrcm_isr(void *arg); ++#endif /* _BRCM_SDH_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c.orig 2011-11-09 13:46:58.237800734 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c 2011-11-09 13:47:16.989566304 -0500 +@@ -0,0 +1,3868 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include "dhd.h" ++#include "wl_cfg80211.h" ++ ++#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ ++ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) ++ ++static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; ++ ++static u32 brcmf_dbg_level = WL_DBG_ERR; ++ ++static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) ++{ ++ dev->driver_data = data; ++} ++ ++static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) ++{ ++ void *data = NULL; ++ ++ if (dev) ++ data = dev->driver_data; ++ return data; ++} ++ ++static ++struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) ++{ ++ struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev); ++ return ci->cfg_priv; ++} ++ ++static bool check_sys_up(struct wiphy *wiphy) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ WL_INFO("device is not ready : status (%d)\n", ++ (int)cfg_priv->status); ++ return false; ++ } ++ return true; ++} ++ ++#define CHAN2G(_channel, _freq, _flags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define CHAN5G(_channel, _flags) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) ++#define RATETAB_ENT(_rateid, _flags) \ ++ { \ ++ .bitrate = RATE_TO_BASE100KBPS(_rateid), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++ } ++ ++static struct ieee80211_rate __wl_rates[] = { ++ RATETAB_ENT(BRCM_RATE_1M, 0), ++ RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(BRCM_RATE_6M, 0), ++ RATETAB_ENT(BRCM_RATE_9M, 0), ++ RATETAB_ENT(BRCM_RATE_12M, 0), ++ RATETAB_ENT(BRCM_RATE_18M, 0), ++ RATETAB_ENT(BRCM_RATE_24M, 0), ++ RATETAB_ENT(BRCM_RATE_36M, 0), ++ RATETAB_ENT(BRCM_RATE_48M, 0), ++ RATETAB_ENT(BRCM_RATE_54M, 0), ++}; ++ ++#define wl_a_rates (__wl_rates + 4) ++#define wl_a_rates_size 8 ++#define wl_g_rates (__wl_rates + 0) ++#define wl_g_rates_size 12 ++ ++static struct ieee80211_channel __wl_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0), ++}; ++ ++static struct ieee80211_channel __wl_5ghz_a_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0), ++ CHAN5G(184, 0), CHAN5G(188, 0), ++ CHAN5G(192, 0), CHAN5G(196, 0), ++ CHAN5G(200, 0), CHAN5G(204, 0), ++ CHAN5G(208, 0), CHAN5G(212, 0), ++ CHAN5G(216, 0), ++}; ++ ++static struct ieee80211_channel __wl_5ghz_n_channels[] = { ++ CHAN5G(32, 0), CHAN5G(34, 0), ++ CHAN5G(36, 0), CHAN5G(38, 0), ++ CHAN5G(40, 0), CHAN5G(42, 0), ++ CHAN5G(44, 0), CHAN5G(46, 0), ++ CHAN5G(48, 0), CHAN5G(50, 0), ++ CHAN5G(52, 0), CHAN5G(54, 0), ++ CHAN5G(56, 0), CHAN5G(58, 0), ++ CHAN5G(60, 0), CHAN5G(62, 0), ++ CHAN5G(64, 0), CHAN5G(66, 0), ++ CHAN5G(68, 0), CHAN5G(70, 0), ++ CHAN5G(72, 0), CHAN5G(74, 0), ++ CHAN5G(76, 0), CHAN5G(78, 0), ++ CHAN5G(80, 0), CHAN5G(82, 0), ++ CHAN5G(84, 0), CHAN5G(86, 0), ++ CHAN5G(88, 0), CHAN5G(90, 0), ++ CHAN5G(92, 0), CHAN5G(94, 0), ++ CHAN5G(96, 0), CHAN5G(98, 0), ++ CHAN5G(100, 0), CHAN5G(102, 0), ++ CHAN5G(104, 0), CHAN5G(106, 0), ++ CHAN5G(108, 0), CHAN5G(110, 0), ++ CHAN5G(112, 0), CHAN5G(114, 0), ++ CHAN5G(116, 0), CHAN5G(118, 0), ++ CHAN5G(120, 0), CHAN5G(122, 0), ++ CHAN5G(124, 0), CHAN5G(126, 0), ++ CHAN5G(128, 0), CHAN5G(130, 0), ++ CHAN5G(132, 0), CHAN5G(134, 0), ++ CHAN5G(136, 0), CHAN5G(138, 0), ++ CHAN5G(140, 0), CHAN5G(142, 0), ++ CHAN5G(144, 0), CHAN5G(145, 0), ++ CHAN5G(146, 0), CHAN5G(147, 0), ++ CHAN5G(148, 0), CHAN5G(149, 0), ++ CHAN5G(150, 0), CHAN5G(151, 0), ++ CHAN5G(152, 0), CHAN5G(153, 0), ++ CHAN5G(154, 0), CHAN5G(155, 0), ++ CHAN5G(156, 0), CHAN5G(157, 0), ++ CHAN5G(158, 0), CHAN5G(159, 0), ++ CHAN5G(160, 0), CHAN5G(161, 0), ++ CHAN5G(162, 0), CHAN5G(163, 0), ++ CHAN5G(164, 0), CHAN5G(165, 0), ++ CHAN5G(166, 0), CHAN5G(168, 0), ++ CHAN5G(170, 0), CHAN5G(172, 0), ++ CHAN5G(174, 0), CHAN5G(176, 0), ++ CHAN5G(178, 0), CHAN5G(180, 0), ++ CHAN5G(182, 0), CHAN5G(184, 0), ++ CHAN5G(186, 0), CHAN5G(188, 0), ++ CHAN5G(190, 0), CHAN5G(192, 0), ++ CHAN5G(194, 0), CHAN5G(196, 0), ++ CHAN5G(198, 0), CHAN5G(200, 0), ++ CHAN5G(202, 0), CHAN5G(204, 0), ++ CHAN5G(206, 0), CHAN5G(208, 0), ++ CHAN5G(210, 0), CHAN5G(212, 0), ++ CHAN5G(214, 0), CHAN5G(216, 0), ++ CHAN5G(218, 0), CHAN5G(220, 0), ++ CHAN5G(222, 0), CHAN5G(224, 0), ++ CHAN5G(226, 0), CHAN5G(228, 0), ++}; ++ ++static struct ieee80211_supported_band __wl_band_2ghz = { ++ .band = IEEE80211_BAND_2GHZ, ++ .channels = __wl_2ghz_channels, ++ .n_channels = ARRAY_SIZE(__wl_2ghz_channels), ++ .bitrates = wl_g_rates, ++ .n_bitrates = wl_g_rates_size, ++}; ++ ++static struct ieee80211_supported_band __wl_band_5ghz_a = { ++ .band = IEEE80211_BAND_5GHZ, ++ .channels = __wl_5ghz_a_channels, ++ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), ++ .bitrates = wl_a_rates, ++ .n_bitrates = wl_a_rates_size, ++}; ++ ++static struct ieee80211_supported_band __wl_band_5ghz_n = { ++ .band = IEEE80211_BAND_5GHZ, ++ .channels = __wl_5ghz_n_channels, ++ .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), ++ .bitrates = wl_a_rates, ++ .n_bitrates = wl_a_rates_size, ++}; ++ ++static const u32 __wl_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ WLAN_CIPHER_SUITE_AES_CMAC, ++}; ++ ++/* tag_ID/length/value_buffer tuple */ ++struct brcmf_tlv { ++ u8 id; ++ u8 len; ++ u8 data[1]; ++}; ++ ++/* Quarter dBm units to mW ++ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 ++ * Table is offset so the last entry is largest mW value that fits in ++ * a u16. ++ */ ++ ++#define QDBM_OFFSET 153 /* Offset for first entry */ ++#define QDBM_TABLE_LEN 40 /* Table size */ ++ ++/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. ++ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 ++ */ ++#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ ++ ++/* Largest mW value that will round down to the last table entry, ++ * QDBM_OFFSET + QDBM_TABLE_LEN-1. ++ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + ++ * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. ++ */ ++#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ ++ ++static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { ++/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ ++/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, ++/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, ++/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, ++/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, ++/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 ++}; ++ ++static u16 brcmf_qdbm_to_mw(u8 qdbm) ++{ ++ uint factor = 1; ++ int idx = qdbm - QDBM_OFFSET; ++ ++ if (idx >= QDBM_TABLE_LEN) ++ /* clamp to max u16 mW value */ ++ return 0xFFFF; ++ ++ /* scale the qdBm index up to the range of the table 0-40 ++ * where an offset of 40 qdBm equals a factor of 10 mW. ++ */ ++ while (idx < 0) { ++ idx += 40; ++ factor *= 10; ++ } ++ ++ /* return the mW value scaled down to the correct factor of 10, ++ * adding in factor/2 to get proper rounding. ++ */ ++ return (nqdBm_to_mW_map[idx] + factor / 2) / factor; ++} ++ ++static u8 brcmf_mw_to_qdbm(u16 mw) ++{ ++ u8 qdbm; ++ int offset; ++ uint mw_uint = mw; ++ uint boundary; ++ ++ /* handle boundary case */ ++ if (mw_uint <= 1) ++ return 0; ++ ++ offset = QDBM_OFFSET; ++ ++ /* move mw into the range of the table */ ++ while (mw_uint < QDBM_TABLE_LOW_BOUND) { ++ mw_uint *= 10; ++ offset -= 40; ++ } ++ ++ for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) { ++ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] - ++ nqdBm_to_mW_map[qdbm]) / 2; ++ if (mw_uint < boundary) ++ break; ++ } ++ ++ qdbm += (u8) offset; ++ ++ return qdbm; ++} ++ ++/* function for reading/writing a single u32 from/to the dongle */ ++static int ++brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) ++{ ++ int err; ++ __le32 par_le = cpu_to_le32(*par); ++ ++ err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32)); ++ *par = le32_to_cpu(par_le); ++ ++ return err; ++} ++ ++static void convert_key_from_CPU(struct brcmf_wsec_key *key, ++ struct brcmf_wsec_key_le *key_le) ++{ ++ key_le->index = cpu_to_le32(key->index); ++ key_le->len = cpu_to_le32(key->len); ++ key_le->algo = cpu_to_le32(key->algo); ++ key_le->flags = cpu_to_le32(key->flags); ++ key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi); ++ key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo); ++ key_le->iv_initialized = cpu_to_le32(key->iv_initialized); ++ memcpy(key_le->data, key->data, sizeof(key->data)); ++ memcpy(key_le->ea, key->ea, sizeof(key->ea)); ++} ++ ++static int send_key_to_dongle(struct net_device *ndev, ++ struct brcmf_wsec_key *key) ++{ ++ int err; ++ struct brcmf_wsec_key_le key_le; ++ ++ convert_key_from_CPU(key, &key_le); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le)); ++ if (err) ++ WL_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct wireless_dev *wdev; ++ s32 infra = 0; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ switch (type) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ WL_ERR("type (%d) : currently we do not support this type\n", ++ type); ++ return -EOPNOTSUPP; ++ case NL80211_IFTYPE_ADHOC: ++ cfg_priv->conf->mode = WL_MODE_IBSS; ++ infra = 0; ++ break; ++ case NL80211_IFTYPE_STATION: ++ cfg_priv->conf->mode = WL_MODE_BSS; ++ infra = 1; ++ break; ++ default: ++ err = -EINVAL; ++ goto done; ++ } ++ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); ++ if (err) { ++ WL_ERR("WLC_SET_INFRA error (%d)\n", err); ++ err = -EAGAIN; ++ } else { ++ wdev = ndev->ieee80211_ptr; ++ wdev->iftype = type; ++ } ++ ++ WL_INFO("IF Type = %s\n", ++ (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); ++ ++done: ++ WL_TRACE("Exit\n"); ++ ++ return err; ++} ++ ++static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val) ++{ ++ s8 buf[BRCMF_DCMD_SMLEN]; ++ u32 len; ++ s32 err = 0; ++ __le32 val_le; ++ ++ val_le = cpu_to_le32(val); ++ len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf, ++ sizeof(buf)); ++ BUG_ON(!len); ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); ++ if (err) ++ WL_ERR("error (%d)\n", err); ++ ++ return err; ++} ++ ++static s32 ++brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) ++{ ++ union { ++ s8 buf[BRCMF_DCMD_SMLEN]; ++ __le32 val; ++ } var; ++ u32 len; ++ u32 data_null; ++ s32 err = 0; ++ ++ len = ++ brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), ++ sizeof(var.buf)); ++ BUG_ON(!len); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len); ++ if (err) ++ WL_ERR("error (%d)\n", err); ++ ++ *retval = le32_to_cpu(var.val); ++ ++ return err; ++} ++ ++static void brcmf_set_mpc(struct net_device *ndev, int mpc) ++{ ++ s32 err = 0; ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ ++ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ err = brcmf_dev_intvar_set(ndev, "mpc", mpc); ++ if (err) { ++ WL_ERR("fail to set mpc\n"); ++ return; ++ } ++ WL_INFO("MPC : %d\n", mpc); ++ } ++} ++ ++static void wl_iscan_prep(struct brcmf_scan_params_le *params_le, ++ struct brcmf_ssid *ssid) ++{ ++ memcpy(params_le->bssid, ether_bcast, ETH_ALEN); ++ params_le->bss_type = DOT11_BSSTYPE_ANY; ++ params_le->scan_type = 0; ++ params_le->channel_num = 0; ++ params_le->nprobes = cpu_to_le32(-1); ++ params_le->active_time = cpu_to_le32(-1); ++ params_le->passive_time = cpu_to_le32(-1); ++ params_le->home_time = cpu_to_le32(-1); ++ if (ssid && ssid->SSID_len) ++ memcpy(¶ms_le->ssid_le, ssid, sizeof(struct brcmf_ssid)); ++} ++ ++static s32 ++brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param, ++ s32 paramlen, void *bufptr, s32 buflen) ++{ ++ s32 iolen; ++ ++ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ BUG_ON(!iolen); ++ ++ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen); ++} ++ ++static s32 ++brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param, ++ s32 paramlen, void *bufptr, s32 buflen) ++{ ++ s32 iolen; ++ ++ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ BUG_ON(!iolen); ++ ++ return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen); ++} ++ ++static s32 ++brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, ++ struct brcmf_ssid *ssid, u16 action) ++{ ++ s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + ++ offsetof(struct brcmf_iscan_params_le, params_le); ++ struct brcmf_iscan_params_le *params; ++ s32 err = 0; ++ ++ if (ssid && ssid->SSID_len) ++ params_size += sizeof(struct brcmf_ssid); ++ params = kzalloc(params_size, GFP_KERNEL); ++ if (!params) ++ return -ENOMEM; ++ BUG_ON(params_size >= BRCMF_DCMD_SMLEN); ++ ++ wl_iscan_prep(¶ms->params_le, ssid); ++ ++ params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); ++ params->action = cpu_to_le16(action); ++ params->scan_duration = cpu_to_le16(0); ++ ++ err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size, ++ iscan->dcmd_buf, BRCMF_DCMD_SMLEN); ++ if (err) { ++ if (err == -EBUSY) ++ WL_INFO("system busy : iscan canceled\n"); ++ else ++ WL_ERR("error (%d)\n", err); ++ } ++ ++ kfree(params); ++ return err; ++} ++ ++static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ struct brcmf_ssid ssid; ++ __le32 passive_scan; ++ s32 err = 0; ++ ++ /* Broadcast scan by default */ ++ memset(&ssid, 0, sizeof(ssid)); ++ ++ iscan->state = WL_ISCAN_STATE_SCANING; ++ ++ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); ++ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan)); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ return err; ++ } ++ brcmf_set_mpc(ndev, 0); ++ cfg_priv->iscan_kickstart = true; ++ err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); ++ if (err) { ++ brcmf_set_mpc(ndev, 1); ++ cfg_priv->iscan_kickstart = false; ++ return err; ++ } ++ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); ++ iscan->timer_on = 1; ++ return err; ++} ++ ++static s32 ++__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request, ++ struct cfg80211_ssid *this_ssid) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct cfg80211_ssid *ssids; ++ struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; ++ __le32 passive_scan; ++ bool iscan_req; ++ bool spec_scan; ++ s32 err = 0; ++ u32 SSID_len; ++ ++ if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { ++ WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); ++ return -EAGAIN; ++ } ++ if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) { ++ WL_ERR("Scanning being aborted : status (%lu)\n", ++ cfg_priv->status); ++ return -EAGAIN; ++ } ++ if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { ++ WL_ERR("Connecting : status (%lu)\n", ++ cfg_priv->status); ++ return -EAGAIN; ++ } ++ ++ iscan_req = false; ++ spec_scan = false; ++ if (request) { ++ /* scan bss */ ++ ssids = request->ssids; ++ if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len)) ++ iscan_req = true; ++ } else { ++ /* scan in ibss */ ++ /* we don't do iscan in ibss */ ++ ssids = this_ssid; ++ } ++ ++ cfg_priv->scan_request = request; ++ set_bit(WL_STATUS_SCANNING, &cfg_priv->status); ++ if (iscan_req) { ++ err = brcmf_do_iscan(cfg_priv); ++ if (!err) ++ return err; ++ else ++ goto scan_out; ++ } else { ++ WL_SCAN("ssid \"%s\", ssid_len (%d)\n", ++ ssids->ssid, ssids->ssid_len); ++ memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); ++ SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); ++ sr->ssid_le.SSID_len = cpu_to_le32(0); ++ if (SSID_len) { ++ memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); ++ sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); ++ spec_scan = true; ++ } else { ++ WL_SCAN("Broadcast scan\n"); ++ } ++ ++ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan)); ++ if (err) { ++ WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); ++ goto scan_out; ++ } ++ brcmf_set_mpc(ndev, 0); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, ++ sizeof(sr->ssid_le)); ++ if (err) { ++ if (err == -EBUSY) ++ WL_INFO("system busy : scan for \"%s\" " ++ "canceled\n", sr->ssid_le.SSID); ++ else ++ WL_ERR("WLC_SCAN error (%d)\n", err); ++ ++ brcmf_set_mpc(ndev, 1); ++ goto scan_out; ++ } ++ } ++ ++ return 0; ++ ++scan_out: ++ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); ++ cfg_priv->scan_request = NULL; ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request) ++{ ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL); ++ if (err) ++ WL_ERR("scan error (%d)\n", err); ++ ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold) ++{ ++ s32 err = 0; ++ ++ err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold); ++ if (err) ++ WL_ERR("Error (%d)\n", err); ++ ++ return err; ++} ++ ++static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) ++{ ++ s32 err = 0; ++ ++ err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold); ++ if (err) ++ WL_ERR("Error (%d)\n", err); ++ ++ return err; ++} ++ ++static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) ++{ ++ s32 err = 0; ++ u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); ++ ++ err = brcmf_exec_dcmd_u32(ndev, cmd, &retry); ++ if (err) { ++ WL_ERR("cmd (%d) , error (%d)\n", cmd, err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD && ++ (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) { ++ cfg_priv->conf->rts_threshold = wiphy->rts_threshold; ++ err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold); ++ if (!err) ++ goto done; ++ } ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD && ++ (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) { ++ cfg_priv->conf->frag_threshold = wiphy->frag_threshold; ++ err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold); ++ if (!err) ++ goto done; ++ } ++ if (changed & WIPHY_PARAM_RETRY_LONG ++ && (cfg_priv->conf->retry_long != wiphy->retry_long)) { ++ cfg_priv->conf->retry_long = wiphy->retry_long; ++ err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true); ++ if (!err) ++ goto done; ++ } ++ if (changed & WIPHY_PARAM_RETRY_SHORT ++ && (cfg_priv->conf->retry_short != wiphy->retry_short)) { ++ cfg_priv->conf->retry_short = wiphy->retry_short; ++ err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false); ++ if (!err) ++ goto done; ++ } ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) ++{ ++ switch (item) { ++ case WL_PROF_SEC: ++ return &cfg_priv->profile->sec; ++ case WL_PROF_BSSID: ++ return &cfg_priv->profile->bssid; ++ case WL_PROF_SSID: ++ return &cfg_priv->profile->ssid; ++ } ++ WL_ERR("invalid item (%d)\n", item); ++ return NULL; ++} ++ ++static s32 ++brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, ++ const struct brcmf_event_msg *e, void *data, s32 item) ++{ ++ s32 err = 0; ++ struct brcmf_ssid *ssid; ++ ++ switch (item) { ++ case WL_PROF_SSID: ++ ssid = (struct brcmf_ssid *) data; ++ memset(cfg_priv->profile->ssid.SSID, 0, ++ sizeof(cfg_priv->profile->ssid.SSID)); ++ memcpy(cfg_priv->profile->ssid.SSID, ++ ssid->SSID, ssid->SSID_len); ++ cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; ++ break; ++ case WL_PROF_BSSID: ++ if (data) ++ memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); ++ else ++ memset(cfg_priv->profile->bssid, 0, ETH_ALEN); ++ break; ++ case WL_PROF_SEC: ++ memcpy(&cfg_priv->profile->sec, data, ++ sizeof(cfg_priv->profile->sec)); ++ break; ++ case WL_PROF_BEACONINT: ++ cfg_priv->profile->beacon_interval = *(u16 *)data; ++ break; ++ case WL_PROF_DTIMPERIOD: ++ cfg_priv->profile->dtim_period = *(u8 *)data; ++ break; ++ default: ++ WL_ERR("unsupported item (%d)\n", item); ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ return err; ++} ++ ++static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) ++{ ++ memset(prof, 0, sizeof(*prof)); ++} ++ ++static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, ++ size_t *join_params_size) ++{ ++ u16 chanspec = 0; ++ ++ if (ch != 0) { ++ if (ch <= CH_MAX_2G_CHANNEL) ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + ++ sizeof(u16); ++ ++ chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); ++ join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); ++ join_params->params_le.chanspec_num = cpu_to_le32(1); ++ ++ WL_CONN("join_params->params.chanspec_list[0]= %#X," ++ "channel %d, chanspec %#X\n", ++ chanspec, ch, chanspec); ++ } ++} ++ ++static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct net_device *ndev = NULL; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ ++ if (cfg_priv->link_up) { ++ ndev = cfg_to_ndev(cfg_priv); ++ WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); ++ if (err) ++ WL_ERR("WLC_DISASSOC failed (%d)\n", err); ++ cfg_priv->link_up = false; ++ } ++ WL_TRACE("Exit\n"); ++} ++ ++static s32 ++brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ibss_params *params) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct brcmf_join_params join_params; ++ size_t join_params_size = 0; ++ s32 err = 0; ++ s32 wsec = 0; ++ s32 bcnprd; ++ struct brcmf_ssid ssid; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ if (params->ssid) ++ WL_CONN("SSID: %s\n", params->ssid); ++ else { ++ WL_CONN("SSID: NULL, Not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ ++ if (params->bssid) ++ WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", ++ params->bssid[0], params->bssid[1], params->bssid[2], ++ params->bssid[3], params->bssid[4], params->bssid[5]); ++ else ++ WL_CONN("No BSSID specified\n"); ++ ++ if (params->channel) ++ WL_CONN("channel: %d\n", params->channel->center_freq); ++ else ++ WL_CONN("no channel specified\n"); ++ ++ if (params->channel_fixed) ++ WL_CONN("fixed channel required\n"); ++ else ++ WL_CONN("no fixed channel required\n"); ++ ++ if (params->ie && params->ie_len) ++ WL_CONN("ie len: %d\n", params->ie_len); ++ else ++ WL_CONN("no ie specified\n"); ++ ++ if (params->beacon_interval) ++ WL_CONN("beacon interval: %d\n", params->beacon_interval); ++ else ++ WL_CONN("no beacon interval specified\n"); ++ ++ if (params->basic_rates) ++ WL_CONN("basic rates: %08X\n", params->basic_rates); ++ else ++ WL_CONN("no basic rates specified\n"); ++ ++ if (params->privacy) ++ WL_CONN("privacy required\n"); ++ else ++ WL_CONN("no privacy required\n"); ++ ++ /* Configure Privacy for starter */ ++ if (params->privacy) ++ wsec |= WEP_ENABLED; ++ ++ err = brcmf_dev_intvar_set(ndev, "wsec", wsec); ++ if (err) { ++ WL_ERR("wsec failed (%d)\n", err); ++ goto done; ++ } ++ ++ /* Configure Beacon Interval for starter */ ++ if (params->beacon_interval) ++ bcnprd = params->beacon_interval; ++ else ++ bcnprd = 100; ++ ++ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd); ++ if (err) { ++ WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); ++ goto done; ++ } ++ ++ /* Configure required join parameter */ ++ memset(&join_params, 0, sizeof(struct brcmf_join_params)); ++ ++ /* SSID */ ++ ssid.SSID_len = min_t(u32, params->ssid_len, 32); ++ memcpy(ssid.SSID, params->ssid, ssid.SSID_len); ++ memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len); ++ join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); ++ join_params_size = sizeof(join_params.ssid_le); ++ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); ++ ++ /* BSSID */ ++ if (params->bssid) { ++ memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN); ++ join_params_size = sizeof(join_params.ssid_le) + ++ BRCMF_ASSOC_PARAMS_FIXED_SIZE; ++ } else { ++ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); ++ } ++ ++ brcmf_update_prof(cfg_priv, NULL, ++ &join_params.params_le.bssid, WL_PROF_BSSID); ++ ++ /* Channel */ ++ if (params->channel) { ++ u32 target_channel; ++ ++ cfg_priv->channel = ++ ieee80211_frequency_to_channel( ++ params->channel->center_freq); ++ if (params->channel_fixed) { ++ /* adding chanspec */ ++ brcmf_ch_to_chanspec(cfg_priv->channel, ++ &join_params, &join_params_size); ++ } ++ ++ /* set channel for starter */ ++ target_channel = cfg_priv->channel; ++ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, ++ &target_channel); ++ if (err) { ++ WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); ++ goto done; ++ } ++ } else ++ cfg_priv->channel = 0; ++ ++ cfg_priv->ibss_starter = false; ++ ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, ++ &join_params, join_params_size); ++ if (err) { ++ WL_ERR("WLC_SET_SSID failed (%d)\n", err); ++ goto done; ++ } ++ ++done: ++ if (err) ++ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ brcmf_link_down(cfg_priv); ++ ++ WL_TRACE("Exit\n"); ++ ++ return err; ++} ++ ++static s32 brcmf_set_wpa_version(struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct brcmf_cfg80211_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; ++ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) ++ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; ++ else ++ val = WPA_AUTH_DISABLED; ++ WL_CONN("setting wpa_auth to 0x%0x\n", val); ++ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); ++ if (err) { ++ WL_ERR("set wpa_auth failed (%d)\n", err); ++ return err; ++ } ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ sec->wpa_versions = sme->crypto.wpa_versions; ++ return err; ++} ++ ++static s32 brcmf_set_auth_type(struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct brcmf_cfg80211_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ ++ switch (sme->auth_type) { ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ val = 0; ++ WL_CONN("open system\n"); ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ val = 1; ++ WL_CONN("shared key\n"); ++ break; ++ case NL80211_AUTHTYPE_AUTOMATIC: ++ val = 2; ++ WL_CONN("automatic\n"); ++ break; ++ case NL80211_AUTHTYPE_NETWORK_EAP: ++ WL_CONN("network eap\n"); ++ default: ++ val = 2; ++ WL_ERR("invalid auth type (%d)\n", sme->auth_type); ++ break; ++ } ++ ++ err = brcmf_dev_intvar_set(ndev, "auth", val); ++ if (err) { ++ WL_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ sec->auth_type = sme->auth_type; ++ return err; ++} ++ ++static s32 ++brcmf_set_set_cipher(struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct brcmf_cfg80211_security *sec; ++ s32 pval = 0; ++ s32 gval = 0; ++ s32 err = 0; ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ switch (sme->crypto.ciphers_pairwise[0]) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ pval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ pval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ pval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ pval = AES_ENABLED; ++ break; ++ default: ++ WL_ERR("invalid cipher pairwise (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ } ++ if (sme->crypto.cipher_group) { ++ switch (sme->crypto.cipher_group) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ gval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ gval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ gval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ gval = AES_ENABLED; ++ break; ++ default: ++ WL_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ WL_CONN("pval (%d) gval (%d)\n", pval, gval); ++ err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ return err; ++ } ++ ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; ++ sec->cipher_group = sme->crypto.cipher_group; ++ ++ return err; ++} ++ ++static s32 ++brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct brcmf_cfg80211_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ ++ if (sme->crypto.n_akm_suites) { ++ err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val); ++ if (err) { ++ WL_ERR("could not get wpa_auth (%d)\n", err); ++ return err; ++ } ++ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA_AUTH_PSK; ++ break; ++ default: ++ WL_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA2_AUTH_PSK; ++ break; ++ default: ++ WL_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ WL_CONN("setting wpa_auth to %d\n", val); ++ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); ++ if (err) { ++ WL_ERR("could not set wpa_auth (%d)\n", err); ++ return err; ++ } ++ } ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ sec->wpa_auth = sme->crypto.akm_suites[0]; ++ ++ return err; ++} ++ ++static s32 ++brcmf_set_wep_sharedkey(struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ struct brcmf_cfg80211_security *sec; ++ struct brcmf_wsec_key key; ++ s32 val; ++ s32 err = 0; ++ ++ WL_CONN("key len (%d)\n", sme->key_len); ++ ++ if (sme->key_len == 0) ++ return 0; ++ ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", ++ sec->wpa_versions, sec->cipher_pairwise); ++ ++ if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) ++ return 0; ++ ++ if (sec->cipher_pairwise & ++ (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) { ++ memset(&key, 0, sizeof(key)); ++ key.len = (u32) sme->key_len; ++ key.index = (u32) sme->key_idx; ++ if (key.len > sizeof(key.data)) { ++ WL_ERR("Too long key length (%u)\n", key.len); ++ return -EINVAL; ++ } ++ memcpy(key.data, sme->key, key.len); ++ key.flags = BRCMF_PRIMARY_KEY; ++ switch (sec->cipher_pairwise) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++ default: ++ WL_ERR("Invalid algorithm (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ /* Set the new key/index */ ++ WL_CONN("key length (%d) key index (%d) algo (%d)\n", ++ key.len, key.index, key.algo); ++ WL_CONN("key \"%s\"\n", key.data); ++ err = send_key_to_dongle(ndev, &key); ++ if (err) ++ return err; ++ ++ if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { ++ WL_CONN("set auth_type to shared key\n"); ++ val = 1; /* shared key */ ++ err = brcmf_dev_intvar_set(ndev, "auth", val); ++ if (err) { ++ WL_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ } ++ } ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct ieee80211_channel *chan = sme->channel; ++ struct brcmf_join_params join_params; ++ size_t join_params_size; ++ struct brcmf_ssid ssid; ++ ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ if (!sme->ssid) { ++ WL_ERR("Invalid ssid\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ ++ if (chan) { ++ cfg_priv->channel = ++ ieee80211_frequency_to_channel(chan->center_freq); ++ WL_CONN("channel (%d), center_req (%d)\n", ++ cfg_priv->channel, chan->center_freq); ++ } else ++ cfg_priv->channel = 0; ++ ++ WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); ++ ++ err = brcmf_set_wpa_version(ndev, sme); ++ if (err) { ++ WL_ERR("wl_set_wpa_version failed (%d)\n", err); ++ goto done; ++ } ++ ++ err = brcmf_set_auth_type(ndev, sme); ++ if (err) { ++ WL_ERR("wl_set_auth_type failed (%d)\n", err); ++ goto done; ++ } ++ ++ err = brcmf_set_set_cipher(ndev, sme); ++ if (err) { ++ WL_ERR("wl_set_set_cipher failed (%d)\n", err); ++ goto done; ++ } ++ ++ err = brcmf_set_key_mgmt(ndev, sme); ++ if (err) { ++ WL_ERR("wl_set_key_mgmt failed (%d)\n", err); ++ goto done; ++ } ++ ++ err = brcmf_set_wep_sharedkey(ndev, sme); ++ if (err) { ++ WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err); ++ goto done; ++ } ++ ++ memset(&join_params, 0, sizeof(join_params)); ++ join_params_size = sizeof(join_params.ssid_le); ++ ++ ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len); ++ memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len); ++ memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len); ++ join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); ++ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); ++ ++ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); ++ ++ if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) ++ WL_CONN("ssid \"%s\", len (%d)\n", ++ ssid.SSID, ssid.SSID_len); ++ ++ brcmf_ch_to_chanspec(cfg_priv->channel, ++ &join_params, &join_params_size); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, ++ &join_params, join_params_size); ++ if (err) ++ WL_ERR("WLC_SET_SSID failed (%d)\n", err); ++ ++done: ++ if (err) ++ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, ++ u16 reason_code) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct brcmf_scb_val_le scbval; ++ s32 err = 0; ++ ++ WL_TRACE("Enter. Reason code = %d\n", reason_code); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status); ++ ++ memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN); ++ scbval.val = cpu_to_le32(reason_code); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, ++ sizeof(struct brcmf_scb_val_le)); ++ if (err) ++ WL_ERR("error (%d)\n", err); ++ ++ cfg_priv->link_up = false; ++ ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, s32 dbm) ++{ ++ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ u16 txpwrmw; ++ s32 err = 0; ++ s32 disable = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ switch (type) { ++ case NL80211_TX_POWER_AUTOMATIC: ++ break; ++ case NL80211_TX_POWER_LIMITED: ++ if (dbm < 0) { ++ WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); ++ err = -EINVAL; ++ goto done; ++ } ++ break; ++ case NL80211_TX_POWER_FIXED: ++ if (dbm < 0) { ++ WL_ERR("TX_POWER_FIXED - dbm is negative\n"); ++ err = -EINVAL; ++ goto done; ++ } ++ break; ++ } ++ /* Make sure radio is off or on as far as software is concerned */ ++ disable = WL_RADIO_SW_DISABLE << 16; ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable); ++ if (err) ++ WL_ERR("WLC_SET_RADIO error (%d)\n", err); ++ ++ if (dbm > 0xffff) ++ txpwrmw = 0xffff; ++ else ++ txpwrmw = (u16) dbm; ++ err = brcmf_dev_intvar_set(ndev, "qtxpower", ++ (s32) (brcmf_mw_to_qdbm(txpwrmw))); ++ if (err) ++ WL_ERR("qtxpower error (%d)\n", err); ++ cfg_priv->conf->tx_power = dbm; ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ s32 txpwrdbm; ++ u8 result; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ goto done; ++ } ++ ++ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); ++ *dbm = (s32) brcmf_qdbm_to_mw(result); ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, bool unicast, bool multicast) ++{ ++ u32 index; ++ u32 wsec; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ WL_CONN("key index (%d)\n", key_idx); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); ++ if (err) { ++ WL_ERR("WLC_GET_WSEC error (%d)\n", err); ++ goto done; ++ } ++ ++ if (wsec & WEP_ENABLED) { ++ /* Just select a new current key */ ++ index = key_idx; ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY, ++ &index); ++ if (err) ++ WL_ERR("error (%d)\n", err); ++ } ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, const u8 *mac_addr, struct key_params *params) ++{ ++ struct brcmf_wsec_key key; ++ struct brcmf_wsec_key_le key_le; ++ s32 err = 0; ++ ++ memset(&key, 0, sizeof(key)); ++ key.index = (u32) key_idx; ++ /* Instead of bcast for ea address for default wep keys, ++ driver needs it to be Null */ ++ if (!is_multicast_ether_addr(mac_addr)) ++ memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); ++ key.len = (u32) params->key_len; ++ /* check for key index change */ ++ if (key.len == 0) { ++ /* key delete */ ++ err = send_key_to_dongle(ndev, &key); ++ if (err) ++ return err; ++ } else { ++ if (key.len > sizeof(key.data)) { ++ WL_ERR("Invalid key length (%d)\n", key.len); ++ return -EINVAL; ++ } ++ ++ WL_CONN("Setting the key index %d\n", key.index); ++ memcpy(key.data, params->key, key.len); ++ ++ if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { ++ u8 keybuf[8]; ++ memcpy(keybuf, &key.data[24], sizeof(keybuf)); ++ memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); ++ memcpy(&key.data[16], keybuf, sizeof(keybuf)); ++ } ++ ++ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ ++ if (params->seq && params->seq_len == 6) { ++ /* rx iv */ ++ u8 *ivptr; ++ ivptr = (u8 *) params->seq; ++ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | ++ (ivptr[3] << 8) | ivptr[2]; ++ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; ++ key.iv_initialized = true; ++ } ++ ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++ default: ++ WL_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ return -EINVAL; ++ } ++ convert_key_from_CPU(&key, &key_le); ++ ++ brcmf_netdev_wait_pend8021x(ndev); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, ++ sizeof(key_le)); ++ if (err) { ++ WL_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ } ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) ++{ ++ struct brcmf_wsec_key key; ++ s32 val; ++ s32 wsec; ++ s32 err = 0; ++ u8 keybuf[8]; ++ ++ WL_TRACE("Enter\n"); ++ WL_CONN("key index (%d)\n", key_idx); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ if (mac_addr) { ++ WL_TRACE("Exit"); ++ return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); ++ } ++ memset(&key, 0, sizeof(key)); ++ ++ key.len = (u32) params->key_len; ++ key.index = (u32) key_idx; ++ ++ if (key.len > sizeof(key.data)) { ++ WL_ERR("Too long key length (%u)\n", key.len); ++ err = -EINVAL; ++ goto done; ++ } ++ memcpy(key.data, params->key, key.len); ++ ++ key.flags = BRCMF_PRIMARY_KEY; ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ memcpy(keybuf, &key.data[24], sizeof(keybuf)); ++ memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); ++ memcpy(&key.data[16], keybuf, sizeof(keybuf)); ++ key.algo = CRYPTO_ALGO_TKIP; ++ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++ default: ++ WL_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ err = -EINVAL; ++ goto done; ++ } ++ ++ err = send_key_to_dongle(ndev, &key); /* Set the new key/index */ ++ if (err) ++ goto done; ++ ++ val = WEP_ENABLED; ++ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); ++ if (err) { ++ WL_ERR("get wsec error (%d)\n", err); ++ goto done; ++ } ++ wsec &= ~(WEP_ENABLED); ++ wsec |= val; ++ err = brcmf_dev_intvar_set(ndev, "wsec", wsec); ++ if (err) { ++ WL_ERR("set wsec error (%d)\n", err); ++ goto done; ++ } ++ ++ val = 1; /* assume shared key. otherwise 0 */ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); ++ if (err) ++ WL_ERR("WLC_SET_AUTH error (%d)\n", err); ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr) ++{ ++ struct brcmf_wsec_key key; ++ s32 err = 0; ++ s32 val; ++ s32 wsec; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ memset(&key, 0, sizeof(key)); ++ ++ key.index = (u32) key_idx; ++ key.flags = BRCMF_PRIMARY_KEY; ++ key.algo = CRYPTO_ALGO_OFF; ++ ++ WL_CONN("key index (%d)\n", key_idx); ++ ++ /* Set the new key/index */ ++ err = send_key_to_dongle(ndev, &key); ++ if (err) { ++ if (err == -EINVAL) { ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) ++ /* we ignore this key index in this case */ ++ WL_ERR("invalid key index (%d)\n", key_idx); ++ } ++ /* Ignore this error, may happen during DISASSOC */ ++ err = -EAGAIN; ++ goto done; ++ } ++ ++ val = 0; ++ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); ++ if (err) { ++ WL_ERR("get wsec error (%d)\n", err); ++ /* Ignore this error, may happen during DISASSOC */ ++ err = -EAGAIN; ++ goto done; ++ } ++ wsec &= ~(WEP_ENABLED); ++ wsec |= val; ++ err = brcmf_dev_intvar_set(ndev, "wsec", wsec); ++ if (err) { ++ WL_ERR("set wsec error (%d)\n", err); ++ /* Ignore this error, may happen during DISASSOC */ ++ err = -EAGAIN; ++ goto done; ++ } ++ ++ val = 0; /* assume open key. otherwise 1 */ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); ++ if (err) { ++ WL_ERR("WLC_SET_AUTH error (%d)\n", err); ++ /* Ignore this error, may happen during DISASSOC */ ++ err = -EAGAIN; ++ } ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, ++ void (*callback) (void *cookie, struct key_params * params)) ++{ ++ struct key_params params; ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct brcmf_cfg80211_security *sec; ++ s32 wsec; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ WL_CONN("key index (%d)\n", key_idx); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ memset(¶ms, 0, sizeof(params)); ++ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); ++ if (err) { ++ WL_ERR("WLC_GET_WSEC error (%d)\n", err); ++ /* Ignore this error, may happen during DISASSOC */ ++ err = -EAGAIN; ++ goto done; ++ } ++ switch (wsec) { ++ case WEP_ENABLED: ++ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); ++ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP40; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); ++ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP104; ++ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); ++ } ++ break; ++ case TKIP_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_TKIP; ++ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case AES_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; ++ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ default: ++ WL_ERR("Invalid algo (0x%x)\n", wsec); ++ err = -EINVAL; ++ goto done; ++ } ++ callback(cookie, ¶ms); ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_idx) ++{ ++ WL_INFO("Not supported\n"); ++ ++ return -EOPNOTSUPP; ++} ++ ++static s32 ++brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, ++ u8 *mac, struct station_info *sinfo) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct brcmf_scb_val_le scb_val; ++ int rssi; ++ s32 rate; ++ s32 err = 0; ++ u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID); ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ if (memcmp(mac, bssid, ETH_ALEN)) { ++ WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X" ++ "wl_bssid-%X:%X:%X:%X:%X:%X\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ bssid[0], bssid[1], bssid[2], bssid[3], ++ bssid[4], bssid[5]); ++ err = -ENOENT; ++ goto done; ++ } ++ ++ /* Report the current tx rate */ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); ++ if (err) { ++ WL_ERR("Could not get rate (%d)\n", err); ++ } else { ++ sinfo->filled |= STATION_INFO_TX_BITRATE; ++ sinfo->txrate.legacy = rate * 5; ++ WL_CONN("Rate %d Mbps\n", rate / 2); ++ } ++ ++ if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { ++ scb_val.val = cpu_to_le32(0); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, ++ sizeof(struct brcmf_scb_val_le)); ++ if (err) ++ WL_ERR("Could not get rssi (%d)\n", err); ++ ++ rssi = le32_to_cpu(scb_val.val); ++ sinfo->filled |= STATION_INFO_SIGNAL; ++ sinfo->signal = rssi; ++ WL_CONN("RSSI %d dBm\n", rssi); ++ } ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, ++ bool enabled, s32 timeout) ++{ ++ s32 pm; ++ s32 err = 0; ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ ++ WL_TRACE("Enter\n"); ++ ++ /* ++ * Powersave enable/disable request is coming from the ++ * cfg80211 even before the interface is up. In that ++ * scenario, driver will be storing the power save ++ * preference in cfg_priv struct to apply this to ++ * FW later while initializing the dongle ++ */ ++ cfg_priv->pwr_save = enabled; ++ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ ++ WL_INFO("Device is not ready," ++ "storing the value in cfg_priv struct\n"); ++ goto done; ++ } ++ ++ pm = enabled ? PM_FAST : PM_OFF; ++ WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); ++ ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm); ++ if (err) { ++ if (err == -ENODEV) ++ WL_ERR("net_device is not ready yet\n"); ++ else ++ WL_ERR("error (%d)\n", err); ++ } ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *addr, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ struct brcm_rateset_le rateset_le; ++ s32 rate; ++ s32 val; ++ s32 err_bg; ++ s32 err_a; ++ u32 legacy; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ /* addr param is always NULL. ignore it */ ++ /* Get current rateset */ ++ err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le, ++ sizeof(rateset_le)); ++ if (err) { ++ WL_ERR("could not get current rateset (%d)\n", err); ++ goto done; ++ } ++ ++ legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); ++ if (!legacy) ++ legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & ++ 0xFFFF); ++ ++ val = wl_g_rates[legacy - 1].bitrate * 100000; ++ ++ if (val < le32_to_cpu(rateset_le.count)) ++ /* Select rate by rateset index */ ++ rate = rateset_le.rates[val] & 0x7f; ++ else ++ /* Specified rate in bps */ ++ rate = val / 500000; ++ ++ WL_CONN("rate %d mbps\n", rate / 2); ++ ++ /* ++ * ++ * Set rate override, ++ * Since the is a/b/g-blind, both a/bg_rate are enforced. ++ */ ++ err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate); ++ err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate); ++ if (err_bg && err_a) { ++ WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); ++ err = err_bg | err_a; ++ } ++ ++done: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, ++ struct brcmf_bss_info *bi) ++{ ++ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); ++ struct ieee80211_channel *notify_channel; ++ struct cfg80211_bss *bss; ++ struct ieee80211_supported_band *band; ++ s32 err = 0; ++ u16 channel; ++ u32 freq; ++ u64 notify_timestamp; ++ u16 notify_capability; ++ u16 notify_interval; ++ u8 *notify_ie; ++ size_t notify_ielen; ++ s32 notify_signal; ++ ++ if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { ++ WL_ERR("Bss info is larger than buffer. Discarding\n"); ++ return 0; ++ } ++ ++ channel = bi->ctl_ch ? bi->ctl_ch : ++ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ ++ notify_capability = le16_to_cpu(bi->capability); ++ notify_interval = le16_to_cpu(bi->beacon_period); ++ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); ++ notify_ielen = le32_to_cpu(bi->ie_length); ++ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; ++ ++ WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], ++ bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); ++ WL_CONN("Channel: %d(%d)\n", channel, freq); ++ WL_CONN("Capability: %X\n", notify_capability); ++ WL_CONN("Beacon interval: %d\n", notify_interval); ++ WL_CONN("Signal: %d\n", notify_signal); ++ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); ++ ++ bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, ++ notify_timestamp, notify_capability, notify_interval, notify_ie, ++ notify_ielen, notify_signal, GFP_KERNEL); ++ ++ if (!bss) { ++ WL_ERR("cfg80211_inform_bss_frame error\n"); ++ return -EINVAL; ++ } ++ ++ return err; ++} ++ ++static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_scan_results *bss_list; ++ struct brcmf_bss_info *bi = NULL; /* must be initialized */ ++ s32 err = 0; ++ int i; ++ ++ bss_list = cfg_priv->bss_list; ++ if (bss_list->version != BRCMF_BSS_INFO_VERSION) { ++ WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", ++ bss_list->version); ++ return -EOPNOTSUPP; ++ } ++ WL_SCAN("scanned AP count (%d)\n", bss_list->count); ++ for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { ++ bi = next_bss(bss_list, bi); ++ err = brcmf_inform_single_bss(cfg_priv, bi); ++ if (err) ++ break; ++ } ++ return err; ++} ++ ++static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, const u8 *bssid) ++{ ++ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); ++ struct ieee80211_channel *notify_channel; ++ struct brcmf_bss_info *bi = NULL; ++ struct ieee80211_supported_band *band; ++ u8 *buf = NULL; ++ s32 err = 0; ++ u16 channel; ++ u32 freq; ++ u64 notify_timestamp; ++ u16 notify_capability; ++ u16 notify_interval; ++ u8 *notify_ie; ++ size_t notify_ielen; ++ s32 notify_signal; ++ ++ WL_TRACE("Enter\n"); ++ ++ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); ++ if (buf == NULL) { ++ err = -ENOMEM; ++ goto CleanUp; ++ } ++ ++ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); ++ if (err) { ++ WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); ++ goto CleanUp; ++ } ++ ++ bi = (struct brcmf_bss_info *)(buf + 4); ++ ++ channel = bi->ctl_ch ? bi->ctl_ch : ++ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ ++ notify_capability = le16_to_cpu(bi->capability); ++ notify_interval = le16_to_cpu(bi->beacon_period); ++ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); ++ notify_ielen = le32_to_cpu(bi->ie_length); ++ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; ++ ++ WL_CONN("channel: %d(%d)\n", channel, freq); ++ WL_CONN("capability: %X\n", notify_capability); ++ WL_CONN("beacon interval: %d\n", notify_interval); ++ WL_CONN("signal: %d\n", notify_signal); ++ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); ++ ++ cfg80211_inform_bss(wiphy, notify_channel, bssid, ++ notify_timestamp, notify_capability, notify_interval, ++ notify_ie, notify_ielen, notify_signal, GFP_KERNEL); ++ ++CleanUp: ++ ++ kfree(buf); ++ ++ WL_TRACE("Exit\n"); ++ ++ return err; ++} ++ ++static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ return cfg_priv->conf->mode == WL_MODE_IBSS; ++} ++ ++/* ++ * Traverse a string of 1-byte tag/1-byte length/variable-length value ++ * triples, returning a pointer to the substring whose first element ++ * matches tag ++ */ ++static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) ++{ ++ struct brcmf_tlv *elt; ++ int totlen; ++ ++ elt = (struct brcmf_tlv *) buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= 2) { ++ int len = elt->len; ++ ++ /* validate remaining totlen */ ++ if ((elt->id == key) && (totlen >= (len + 2))) ++ return elt; ++ ++ elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2)); ++ totlen -= (len + 2); ++ } ++ ++ return NULL; ++} ++ ++static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_bss_info *bi; ++ struct brcmf_ssid *ssid; ++ struct brcmf_tlv *tim; ++ u16 beacon_interval; ++ u8 dtim_period; ++ size_t ie_len; ++ u8 *ie; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (brcmf_is_ibssmode(cfg_priv)) ++ return err; ++ ++ ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); ++ ++ *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); ++ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, ++ cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); ++ if (err) { ++ WL_ERR("Could not get bss info %d\n", err); ++ goto update_bss_info_out; ++ } ++ ++ bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); ++ err = brcmf_inform_single_bss(cfg_priv, bi); ++ if (err) ++ goto update_bss_info_out; ++ ++ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); ++ ie_len = le32_to_cpu(bi->ie_length); ++ beacon_interval = le16_to_cpu(bi->beacon_period); ++ ++ tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM); ++ if (tim) ++ dtim_period = tim->data[1]; ++ else { ++ /* ++ * active scan was done so we could not get dtim ++ * information out of probe response. ++ * so we speficially query dtim information to dongle. ++ */ ++ u32 var; ++ err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), ++ "dtim_assoc", &var); ++ if (err) { ++ WL_ERR("wl dtim_assoc failed (%d)\n", err); ++ goto update_bss_info_out; ++ } ++ dtim_period = (u8)var; ++ } ++ ++ brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); ++ brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); ++ ++update_bss_info_out: ++ WL_TRACE("Exit"); ++ return err; ++} ++ ++static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); ++ struct brcmf_ssid ssid; ++ ++ if (cfg_priv->iscan_on) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ ++ cancel_work_sync(&iscan->work); ++ ++ /* Abort iscan running in FW */ ++ memset(&ssid, 0, sizeof(ssid)); ++ brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); ++ } ++} ++ ++static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, ++ bool aborted) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ ++ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { ++ WL_ERR("Scan complete while device not scanning\n"); ++ return; ++ } ++ if (cfg_priv->scan_request) { ++ WL_SCAN("ISCAN Completed scan: %s\n", ++ aborted ? "Aborted" : "Done"); ++ cfg80211_scan_done(cfg_priv->scan_request, aborted); ++ brcmf_set_mpc(ndev, 1); ++ cfg_priv->scan_request = NULL; ++ } ++ cfg_priv->iscan_kickstart = false; ++} ++ ++static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) ++{ ++ if (iscan->state != WL_ISCAN_STATE_IDLE) { ++ WL_SCAN("wake up iscan\n"); ++ schedule_work(&iscan->work); ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++static s32 ++brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, ++ struct brcmf_scan_results **bss_list) ++{ ++ struct brcmf_iscan_results list; ++ struct brcmf_scan_results *results; ++ struct brcmf_scan_results_le *results_le; ++ struct brcmf_iscan_results *list_buf; ++ s32 err = 0; ++ ++ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); ++ list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; ++ results = &list_buf->results; ++ results_le = &list_buf->results_le; ++ results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; ++ results->version = 0; ++ results->count = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); ++ err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list, ++ BRCMF_ISCAN_RESULTS_FIXED_SIZE, ++ iscan->scan_buf, WL_ISCAN_BUF_MAX); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ return err; ++ } ++ results->buflen = le32_to_cpu(results_le->buflen); ++ results->version = le32_to_cpu(results_le->version); ++ results->count = le32_to_cpu(results_le->count); ++ WL_SCAN("results->count = %d\n", results_le->count); ++ WL_SCAN("results->buflen = %d\n", results_le->buflen); ++ *status = le32_to_cpu(list_buf->status_le); ++ WL_SCAN("status = %d\n", *status); ++ *bss_list = results; ++ ++ return err; ++} ++ ++static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ brcmf_inform_bss(cfg_priv); ++ brcmf_notify_iscan_complete(iscan, false); ++ ++ return err; ++} ++ ++static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; ++ s32 err = 0; ++ ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; ++ s32 err = 0; ++ ++ brcmf_inform_bss(cfg_priv); ++ brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ brcmf_notify_iscan_complete(iscan, true); ++ ++ return err; ++} ++ ++static void brcmf_cfg80211_iscan_handler(struct work_struct *work) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = ++ container_of(work, struct brcmf_cfg80211_iscan_ctrl, ++ work); ++ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); ++ struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; ++ u32 status = BRCMF_SCAN_RESULTS_PARTIAL; ++ ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ ++ if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { ++ status = BRCMF_SCAN_RESULTS_ABORTED; ++ WL_ERR("Abort iscan\n"); ++ } ++ ++ el->handler[status](cfg_priv); ++} ++ ++static void brcmf_iscan_timer(unsigned long data) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = ++ (struct brcmf_cfg80211_iscan_ctrl *)data; ++ ++ if (iscan) { ++ iscan->timer_on = 0; ++ WL_SCAN("timer expired\n"); ++ brcmf_wakeup_iscan(iscan); ++ } ++} ++ ++static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); ++ ++ if (cfg_priv->iscan_on) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); ++ } ++ ++ return 0; ++} ++ ++static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) ++{ ++ memset(el, 0, sizeof(*el)); ++ el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; ++ el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; ++ el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; ++ el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; ++ el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; ++} ++ ++static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); ++ int err = 0; ++ ++ if (cfg_priv->iscan_on) { ++ iscan->ndev = cfg_to_ndev(cfg_priv); ++ brcmf_init_iscan_eloop(&iscan->el); ++ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; ++ init_timer(&iscan->timer); ++ iscan->timer.data = (unsigned long) iscan; ++ iscan->timer.function = brcmf_iscan_timer; ++ err = brcmf_invoke_iscan(cfg_priv); ++ if (!err) ++ iscan->data = cfg_priv; ++ } ++ ++ return err; ++} ++ ++static void brcmf_delay(u32 ms) ++{ ++ if (ms < 1000 / HZ) { ++ cond_resched(); ++ mdelay(ms); ++ } else { ++ msleep(ms); ++ } ++} ++ ++static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ ++ /* ++ * Check for WL_STATUS_READY before any function call which ++ * could result is bus access. Don't block the resume for ++ * any driver error conditions ++ */ ++ WL_TRACE("Enter\n"); ++ ++ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) ++ brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); ++ ++ WL_TRACE("Exit\n"); ++ return 0; ++} ++ ++static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, ++ struct cfg80211_wowlan *wow) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ ++ WL_TRACE("Enter\n"); ++ ++ /* ++ * Check for WL_STATUS_READY before any function call which ++ * could result is bus access. Don't block the suspend for ++ * any driver error conditions ++ */ ++ ++ /* ++ * While going to suspend if associated with AP disassociate ++ * from AP to save power while system is in suspended state ++ */ ++ if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || ++ test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && ++ test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ WL_INFO("Disassociating from AP" ++ " while entering suspend state\n"); ++ brcmf_link_down(cfg_priv); ++ ++ /* ++ * Make sure WPA_Supplicant receives all the event ++ * generated due to DISASSOC call to the fw to keep ++ * the state fw and WPA_Supplicant state consistent ++ */ ++ brcmf_delay(500); ++ } ++ ++ set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); ++ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) ++ brcmf_term_iscan(cfg_priv); ++ ++ if (cfg_priv->scan_request) { ++ /* Indidate scan abort to cfg80211 layer */ ++ WL_INFO("Terminating scan in progress\n"); ++ cfg80211_scan_done(cfg_priv->scan_request, true); ++ cfg_priv->scan_request = NULL; ++ } ++ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); ++ clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); ++ ++ /* Turn off watchdog timer */ ++ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ WL_INFO("Enable MPC\n"); ++ brcmf_set_mpc(ndev, 1); ++ } ++ ++ WL_TRACE("Exit\n"); ++ ++ return 0; ++} ++ ++static __used s32 ++brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ u32 buflen; ++ ++ buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf, ++ WL_DCMD_LEN_MAX); ++ BUG_ON(!buflen); ++ ++ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf, ++ buflen); ++} ++ ++static s32 ++brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, ++ s32 buf_len) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ u32 len; ++ s32 err = 0; ++ ++ len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf, ++ WL_DCMD_LEN_MAX); ++ BUG_ON(!len); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf, ++ WL_DCMD_LEN_MAX); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ return err; ++ } ++ memcpy(buf, cfg_priv->dcmd_buf, buf_len); ++ ++ return err; ++} ++ ++static __used s32 ++brcmf_update_pmklist(struct net_device *ndev, ++ struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) ++{ ++ int i, j; ++ int pmkid_len; ++ ++ pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); ++ ++ WL_CONN("No of elements %d\n", pmkid_len); ++ for (i = 0; i < pmkid_len; i++) { ++ WL_CONN("PMKID[%d]: %pM =\n", i, ++ &pmk_list->pmkids.pmkid[i].BSSID); ++ for (j = 0; j < WLAN_PMKID_LEN; j++) ++ WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); ++ } ++ ++ if (!err) ++ brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list, ++ sizeof(*pmk_list)); ++ ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; ++ s32 err = 0; ++ int i; ++ int pmkid_len; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ pmkid_len = le32_to_cpu(pmkids->npmkid); ++ for (i = 0; i < pmkid_len; i++) ++ if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) ++ break; ++ if (i < WL_NUM_PMKIDS_MAX) { ++ memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); ++ memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); ++ if (i == pmkid_len) { ++ pmkid_len++; ++ pmkids->npmkid = cpu_to_le32(pmkid_len); ++ } ++ } else ++ err = -EINVAL; ++ ++ WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", ++ pmkids->pmkid[pmkid_len].BSSID); ++ for (i = 0; i < WLAN_PMKID_LEN; i++) ++ WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); ++ ++ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); ++ ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ struct pmkid_list pmkid; ++ s32 err = 0; ++ int i, pmkid_len; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); ++ memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); ++ ++ WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", ++ &pmkid.pmkid[0].BSSID); ++ for (i = 0; i < WLAN_PMKID_LEN; i++) ++ WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); ++ ++ pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid); ++ for (i = 0; i < pmkid_len; i++) ++ if (!memcmp ++ (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, ++ ETH_ALEN)) ++ break; ++ ++ if ((pmkid_len > 0) ++ && (i < pmkid_len)) { ++ memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0, ++ sizeof(struct pmkid)); ++ for (; i < (pmkid_len - 1); i++) { ++ memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, ++ &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID, ++ ETH_ALEN); ++ memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID, ++ &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID, ++ WLAN_PMKID_LEN); ++ } ++ cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1); ++ } else ++ err = -EINVAL; ++ ++ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); ++ ++ WL_TRACE("Exit\n"); ++ return err; ++ ++} ++ ++static s32 ++brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ if (!check_sys_up(wiphy)) ++ return -EIO; ++ ++ memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list)); ++ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); ++ ++ WL_TRACE("Exit\n"); ++ return err; ++ ++} ++ ++static struct cfg80211_ops wl_cfg80211_ops = { ++ .change_virtual_intf = brcmf_cfg80211_change_iface, ++ .scan = brcmf_cfg80211_scan, ++ .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, ++ .join_ibss = brcmf_cfg80211_join_ibss, ++ .leave_ibss = brcmf_cfg80211_leave_ibss, ++ .get_station = brcmf_cfg80211_get_station, ++ .set_tx_power = brcmf_cfg80211_set_tx_power, ++ .get_tx_power = brcmf_cfg80211_get_tx_power, ++ .add_key = brcmf_cfg80211_add_key, ++ .del_key = brcmf_cfg80211_del_key, ++ .get_key = brcmf_cfg80211_get_key, ++ .set_default_key = brcmf_cfg80211_config_default_key, ++ .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, ++ .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, ++ .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, ++ .connect = brcmf_cfg80211_connect, ++ .disconnect = brcmf_cfg80211_disconnect, ++ .suspend = brcmf_cfg80211_suspend, ++ .resume = brcmf_cfg80211_resume, ++ .set_pmksa = brcmf_cfg80211_set_pmksa, ++ .del_pmksa = brcmf_cfg80211_del_pmksa, ++ .flush_pmksa = brcmf_cfg80211_flush_pmksa ++}; ++ ++static s32 brcmf_mode_to_nl80211_iftype(s32 mode) ++{ ++ s32 err = 0; ++ ++ switch (mode) { ++ case WL_MODE_BSS: ++ return NL80211_IFTYPE_STATION; ++ case WL_MODE_IBSS: ++ return NL80211_IFTYPE_ADHOC; ++ default: ++ return NL80211_IFTYPE_UNSPECIFIED; ++ } ++ ++ return err; ++} ++ ++static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, ++ struct device *ndev) ++{ ++ struct wireless_dev *wdev; ++ s32 err = 0; ++ ++ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); ++ if (!wdev) ++ return ERR_PTR(-ENOMEM); ++ ++ wdev->wiphy = ++ wiphy_new(&wl_cfg80211_ops, ++ sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); ++ if (!wdev->wiphy) { ++ WL_ERR("Couldn not allocate wiphy device\n"); ++ err = -ENOMEM; ++ goto wiphy_new_out; ++ } ++ set_wiphy_dev(wdev->wiphy, ndev); ++ wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; ++ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; ++ wdev->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); ++ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; ++ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set ++ * it as 11a by default. ++ * This will be updated with ++ * 11n phy tables in ++ * "ifconfig up" ++ * if phy has 11n capability ++ */ ++ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ wdev->wiphy->cipher_suites = __wl_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); ++ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power ++ * save mode ++ * by default ++ */ ++ err = wiphy_register(wdev->wiphy); ++ if (err < 0) { ++ WL_ERR("Couldn not register wiphy device (%d)\n", err); ++ goto wiphy_register_out; ++ } ++ return wdev; ++ ++wiphy_register_out: ++ wiphy_free(wdev->wiphy); ++ ++wiphy_new_out: ++ kfree(wdev); ++ ++ return ERR_PTR(err); ++} ++ ++static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct wireless_dev *wdev = cfg_priv->wdev; ++ ++ if (!wdev) { ++ WL_ERR("wdev is invalid\n"); ++ return; ++ } ++ wiphy_unregister(wdev->wiphy); ++ wiphy_free(wdev->wiphy); ++ kfree(wdev); ++ cfg_priv->wdev = NULL; ++} ++ ++static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, ++ const struct brcmf_event_msg *e) ++{ ++ u32 event = be32_to_cpu(e->event_type); ++ u32 status = be32_to_cpu(e->status); ++ ++ if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { ++ WL_CONN("Processing set ssid\n"); ++ cfg_priv->link_up = true; ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, ++ const struct brcmf_event_msg *e) ++{ ++ u32 event = be32_to_cpu(e->event_type); ++ u16 flags = be16_to_cpu(e->flags); ++ ++ if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { ++ WL_CONN("Processing link down\n"); ++ return true; ++ } ++ return false; ++} ++ ++static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, ++ const struct brcmf_event_msg *e) ++{ ++ u32 event = be32_to_cpu(e->event_type); ++ u32 status = be32_to_cpu(e->status); ++ ++ if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { ++ WL_CONN("Processing Link %s & no network found\n", ++ be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? ++ "up" : "down"); ++ return true; ++ } ++ ++ if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) { ++ WL_CONN("Processing connecting & no network found\n"); ++ return true; ++ } ++ ++ return false; ++} ++ ++static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); ++ ++ kfree(conn_info->req_ie); ++ conn_info->req_ie = NULL; ++ conn_info->req_ie_len = 0; ++ kfree(conn_info->resp_ie); ++ conn_info->resp_ie = NULL; ++ conn_info->resp_ie_len = 0; ++} ++ ++static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct net_device *ndev = cfg_to_ndev(cfg_priv); ++ struct brcmf_cfg80211_assoc_ielen_le *assoc_info; ++ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); ++ u32 req_len; ++ u32 resp_len; ++ s32 err = 0; ++ ++ brcmf_clear_assoc_ies(cfg_priv); ++ ++ err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf, ++ WL_ASSOC_INFO_MAX); ++ if (err) { ++ WL_ERR("could not get assoc info (%d)\n", err); ++ return err; ++ } ++ assoc_info = ++ (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf; ++ req_len = le32_to_cpu(assoc_info->req_len); ++ resp_len = le32_to_cpu(assoc_info->resp_len); ++ if (req_len) { ++ err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", ++ cfg_priv->extra_buf, ++ WL_ASSOC_INFO_MAX); ++ if (err) { ++ WL_ERR("could not get assoc req (%d)\n", err); ++ return err; ++ } ++ conn_info->req_ie_len = req_len; ++ conn_info->req_ie = ++ kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len, ++ GFP_KERNEL); ++ } else { ++ conn_info->req_ie_len = 0; ++ conn_info->req_ie = NULL; ++ } ++ if (resp_len) { ++ err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", ++ cfg_priv->extra_buf, ++ WL_ASSOC_INFO_MAX); ++ if (err) { ++ WL_ERR("could not get assoc resp (%d)\n", err); ++ return err; ++ } ++ conn_info->resp_ie_len = resp_len; ++ conn_info->resp_ie = ++ kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len, ++ GFP_KERNEL); ++ } else { ++ conn_info->resp_ie_len = 0; ++ conn_info->resp_ie = NULL; ++ } ++ WL_CONN("req len (%d) resp len (%d)\n", ++ conn_info->req_ie_len, conn_info->resp_ie_len); ++ ++ return err; ++} ++ ++static s32 ++brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e) ++{ ++ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); ++ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); ++ struct brcmf_channel_info_le channel_le; ++ struct ieee80211_channel *notify_channel; ++ struct ieee80211_supported_band *band; ++ u32 freq; ++ s32 err = 0; ++ u32 target_channel; ++ ++ WL_TRACE("Enter\n"); ++ ++ brcmf_get_assoc_ies(cfg_priv); ++ brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID); ++ brcmf_update_bss_info(cfg_priv); ++ ++ brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, ++ sizeof(channel_le)); ++ ++ target_channel = le32_to_cpu(channel_le.target_channel); ++ WL_CONN("Roamed to channel %d\n", target_channel); ++ ++ if (target_channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ ++ freq = ieee80211_channel_to_frequency(target_channel, band->band); ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ cfg80211_roamed(ndev, notify_channel, ++ (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ++ conn_info->req_ie, conn_info->req_ie_len, ++ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); ++ WL_CONN("Report roaming result\n"); ++ ++ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, const struct brcmf_event_msg *e, ++ bool completed) ++{ ++ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ ++ if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { ++ if (completed) { ++ brcmf_get_assoc_ies(cfg_priv); ++ brcmf_update_prof(cfg_priv, NULL, &e->addr, ++ WL_PROF_BSSID); ++ brcmf_update_bss_info(cfg_priv); ++ } ++ cfg80211_connect_result(ndev, ++ (u8 *)brcmf_read_prof(cfg_priv, ++ WL_PROF_BSSID), ++ conn_info->req_ie, ++ conn_info->req_ie_len, ++ conn_info->resp_ie, ++ conn_info->resp_ie_len, ++ completed ? WLAN_STATUS_SUCCESS : ++ WLAN_STATUS_AUTH_TIMEOUT, ++ GFP_KERNEL); ++ if (completed) ++ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); ++ WL_CONN("Report connect result - connection %s\n", ++ completed ? "succeeded" : "failed"); ++ } ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ s32 err = 0; ++ ++ if (brcmf_is_linkup(cfg_priv, e)) { ++ WL_CONN("Linkup\n"); ++ if (brcmf_is_ibssmode(cfg_priv)) { ++ brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, ++ WL_PROF_BSSID); ++ wl_inform_ibss(cfg_priv, ndev, e->addr); ++ cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); ++ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); ++ } else ++ brcmf_bss_connect_done(cfg_priv, ndev, e, true); ++ } else if (brcmf_is_linkdown(cfg_priv, e)) { ++ WL_CONN("Linkdown\n"); ++ if (brcmf_is_ibssmode(cfg_priv)) { ++ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ if (test_and_clear_bit(WL_STATUS_CONNECTED, ++ &cfg_priv->status)) ++ brcmf_link_down(cfg_priv); ++ } else { ++ brcmf_bss_connect_done(cfg_priv, ndev, e, false); ++ if (test_and_clear_bit(WL_STATUS_CONNECTED, ++ &cfg_priv->status)) { ++ cfg80211_disconnected(ndev, 0, NULL, 0, ++ GFP_KERNEL); ++ brcmf_link_down(cfg_priv); ++ } ++ } ++ brcmf_init_prof(cfg_priv->profile); ++ } else if (brcmf_is_nonetwork(cfg_priv, e)) { ++ if (brcmf_is_ibssmode(cfg_priv)) ++ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); ++ else ++ brcmf_bss_connect_done(cfg_priv, ndev, e, false); ++ } ++ ++ return err; ++} ++ ++static s32 ++brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ s32 err = 0; ++ u32 event = be32_to_cpu(e->event_type); ++ u32 status = be32_to_cpu(e->status); ++ ++ if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { ++ if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) ++ brcmf_bss_roaming_done(cfg_priv, ndev, e); ++ else ++ brcmf_bss_connect_done(cfg_priv, ndev, e, true); ++ } ++ ++ return err; ++} ++ ++static s32 ++brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ u16 flags = be16_to_cpu(e->flags); ++ enum nl80211_key_type key_type; ++ ++ if (flags & BRCMF_EVENT_MSG_GROUP) ++ key_type = NL80211_KEYTYPE_GROUP; ++ else ++ key_type = NL80211_KEYTYPE_PAIRWISE; ++ ++ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, ++ NULL, GFP_KERNEL); ++ ++ return 0; ++} ++ ++static s32 ++brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ struct brcmf_channel_info_le channel_inform_le; ++ struct brcmf_scan_results_le *bss_list_le; ++ u32 len = WL_SCAN_BUF_MAX; ++ s32 err = 0; ++ bool scan_abort = false; ++ u32 scan_channel; ++ ++ WL_TRACE("Enter\n"); ++ ++ if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) { ++ WL_TRACE("Exit\n"); ++ return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv)); ++ } ++ ++ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { ++ WL_ERR("Scan complete while device not scanning\n"); ++ scan_abort = true; ++ err = -EINVAL; ++ goto scan_done_out; ++ } ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le, ++ sizeof(channel_inform_le)); ++ if (err) { ++ WL_ERR("scan busy (%d)\n", err); ++ scan_abort = true; ++ goto scan_done_out; ++ } ++ scan_channel = le32_to_cpu(channel_inform_le.scan_channel); ++ if (scan_channel) ++ WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); ++ cfg_priv->bss_list = cfg_priv->scan_results; ++ bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list; ++ ++ memset(cfg_priv->scan_results, 0, len); ++ bss_list_le->buflen = cpu_to_le32(len); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, ++ cfg_priv->scan_results, len); ++ if (err) { ++ WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); ++ err = -EINVAL; ++ scan_abort = true; ++ goto scan_done_out; ++ } ++ cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); ++ cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version); ++ cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count); ++ ++ err = brcmf_inform_bss(cfg_priv); ++ if (err) { ++ scan_abort = true; ++ goto scan_done_out; ++ } ++ ++scan_done_out: ++ if (cfg_priv->scan_request) { ++ WL_SCAN("calling cfg80211_scan_done\n"); ++ cfg80211_scan_done(cfg_priv->scan_request, scan_abort); ++ brcmf_set_mpc(ndev, 1); ++ cfg_priv->scan_request = NULL; ++ } ++ ++ WL_TRACE("Exit\n"); ++ ++ return err; ++} ++ ++static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) ++{ ++ conf->mode = (u32)-1; ++ conf->frag_threshold = (u32)-1; ++ conf->rts_threshold = (u32)-1; ++ conf->retry_short = (u32)-1; ++ conf->retry_long = (u32)-1; ++ conf->tx_power = -1; ++} ++ ++static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) ++{ ++ memset(el, 0, sizeof(*el)); ++ el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; ++ el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; ++ el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; ++ el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; ++ el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; ++} ++ ++static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ kfree(cfg_priv->scan_results); ++ cfg_priv->scan_results = NULL; ++ kfree(cfg_priv->bss_info); ++ cfg_priv->bss_info = NULL; ++ kfree(cfg_priv->conf); ++ cfg_priv->conf = NULL; ++ kfree(cfg_priv->profile); ++ cfg_priv->profile = NULL; ++ kfree(cfg_priv->scan_req_int); ++ cfg_priv->scan_req_int = NULL; ++ kfree(cfg_priv->dcmd_buf); ++ cfg_priv->dcmd_buf = NULL; ++ kfree(cfg_priv->extra_buf); ++ cfg_priv->extra_buf = NULL; ++ kfree(cfg_priv->iscan); ++ cfg_priv->iscan = NULL; ++ kfree(cfg_priv->pmk_list); ++ cfg_priv->pmk_list = NULL; ++} ++ ++static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); ++ if (!cfg_priv->scan_results) ++ goto init_priv_mem_out; ++ cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL); ++ if (!cfg_priv->conf) ++ goto init_priv_mem_out; ++ cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL); ++ if (!cfg_priv->profile) ++ goto init_priv_mem_out; ++ cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); ++ if (!cfg_priv->bss_info) ++ goto init_priv_mem_out; ++ cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int), ++ GFP_KERNEL); ++ if (!cfg_priv->scan_req_int) ++ goto init_priv_mem_out; ++ cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); ++ if (!cfg_priv->dcmd_buf) ++ goto init_priv_mem_out; ++ cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); ++ if (!cfg_priv->extra_buf) ++ goto init_priv_mem_out; ++ cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL); ++ if (!cfg_priv->iscan) ++ goto init_priv_mem_out; ++ cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL); ++ if (!cfg_priv->pmk_list) ++ goto init_priv_mem_out; ++ ++ return 0; ++ ++init_priv_mem_out: ++ brcmf_deinit_priv_mem(cfg_priv); ++ ++ return -ENOMEM; ++} ++ ++/* ++* retrieve first queued event from head ++*/ ++ ++static struct brcmf_cfg80211_event_q *brcmf_deq_event( ++ struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_event_q *e = NULL; ++ ++ spin_lock_irq(&cfg_priv->evt_q_lock); ++ if (!list_empty(&cfg_priv->evt_q_list)) { ++ e = list_first_entry(&cfg_priv->evt_q_list, ++ struct brcmf_cfg80211_event_q, evt_q_list); ++ list_del(&e->evt_q_list); ++ } ++ spin_unlock_irq(&cfg_priv->evt_q_lock); ++ ++ return e; ++} ++ ++/* ++** push event to tail of the queue ++*/ ++ ++static s32 ++brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, ++ const struct brcmf_event_msg *msg) ++{ ++ struct brcmf_cfg80211_event_q *e; ++ s32 err = 0; ++ ++ e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); ++ if (!e) ++ return -ENOMEM; ++ ++ e->etype = event; ++ memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); ++ ++ spin_lock_irq(&cfg_priv->evt_q_lock); ++ list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list); ++ spin_unlock_irq(&cfg_priv->evt_q_lock); ++ ++ return err; ++} ++ ++static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) ++{ ++ kfree(e); ++} ++ ++static void brcmf_cfg80211_event_handler(struct work_struct *work) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv = ++ container_of(work, struct brcmf_cfg80211_priv, ++ event_work); ++ struct brcmf_cfg80211_event_q *e; ++ ++ e = brcmf_deq_event(cfg_priv); ++ if (unlikely(!e)) { ++ WL_ERR("event queue empty...\n"); ++ return; ++ } ++ ++ do { ++ WL_INFO("event type (%d)\n", e->etype); ++ if (cfg_priv->el.handler[e->etype]) ++ cfg_priv->el.handler[e->etype](cfg_priv, ++ cfg_to_ndev(cfg_priv), ++ &e->emsg, e->edata); ++ else ++ WL_INFO("Unknown Event (%d): ignoring\n", e->etype); ++ brcmf_put_event(e); ++ } while ((e = brcmf_deq_event(cfg_priv))); ++ ++} ++ ++static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ spin_lock_init(&cfg_priv->evt_q_lock); ++ INIT_LIST_HEAD(&cfg_priv->evt_q_list); ++} ++ ++static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct brcmf_cfg80211_event_q *e; ++ ++ spin_lock_irq(&cfg_priv->evt_q_lock); ++ while (!list_empty(&cfg_priv->evt_q_list)) { ++ e = list_first_entry(&cfg_priv->evt_q_list, ++ struct brcmf_cfg80211_event_q, evt_q_list); ++ list_del(&e->evt_q_list); ++ kfree(e); ++ } ++ spin_unlock_irq(&cfg_priv->evt_q_lock); ++} ++ ++static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ s32 err = 0; ++ ++ cfg_priv->scan_request = NULL; ++ cfg_priv->pwr_save = true; ++ cfg_priv->iscan_on = true; /* iscan on & off switch. ++ we enable iscan per default */ ++ cfg_priv->roam_on = true; /* roam on & off switch. ++ we enable roam per default */ ++ ++ cfg_priv->iscan_kickstart = false; ++ cfg_priv->active_scan = true; /* we do active scan for ++ specific scan per default */ ++ cfg_priv->dongle_up = false; /* dongle is not up yet */ ++ brcmf_init_eq(cfg_priv); ++ err = brcmf_init_priv_mem(cfg_priv); ++ if (err) ++ return err; ++ INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler); ++ brcmf_init_eloop_handler(&cfg_priv->el); ++ mutex_init(&cfg_priv->usr_sync); ++ err = brcmf_init_iscan(cfg_priv); ++ if (err) ++ return err; ++ brcmf_init_conf(cfg_priv->conf); ++ brcmf_init_prof(cfg_priv->profile); ++ brcmf_link_down(cfg_priv); ++ ++ return err; ++} ++ ++static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ cancel_work_sync(&cfg_priv->event_work); ++ cfg_priv->dongle_up = false; /* dongle down */ ++ brcmf_flush_eq(cfg_priv); ++ brcmf_link_down(cfg_priv); ++ brcmf_term_iscan(cfg_priv); ++ brcmf_deinit_priv_mem(cfg_priv); ++} ++ ++struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, ++ struct device *busdev, ++ void *data) ++{ ++ struct wireless_dev *wdev; ++ struct brcmf_cfg80211_priv *cfg_priv; ++ struct brcmf_cfg80211_iface *ci; ++ struct brcmf_cfg80211_dev *cfg_dev; ++ s32 err = 0; ++ ++ if (!ndev) { ++ WL_ERR("ndev is invalid\n"); ++ return NULL; ++ } ++ cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL); ++ if (!cfg_dev) ++ return NULL; ++ ++ wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev); ++ if (IS_ERR(wdev)) { ++ kfree(cfg_dev); ++ return NULL; ++ } ++ ++ wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); ++ cfg_priv = wdev_to_cfg(wdev); ++ cfg_priv->wdev = wdev; ++ cfg_priv->pub = data; ++ ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; ++ ci->cfg_priv = cfg_priv; ++ ndev->ieee80211_ptr = wdev; ++ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); ++ wdev->netdev = ndev; ++ err = wl_init_priv(cfg_priv); ++ if (err) { ++ WL_ERR("Failed to init iwm_priv (%d)\n", err); ++ goto cfg80211_attach_out; ++ } ++ brcmf_set_drvdata(cfg_dev, ci); ++ ++ return cfg_dev; ++ ++cfg80211_attach_out: ++ brcmf_free_wdev(cfg_priv); ++ kfree(cfg_dev); ++ return NULL; ++} ++ ++void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv; ++ ++ cfg_priv = brcmf_priv_get(cfg_dev); ++ ++ wl_deinit_priv(cfg_priv); ++ brcmf_free_wdev(cfg_priv); ++ brcmf_set_drvdata(cfg_dev, NULL); ++ kfree(cfg_dev); ++} ++ ++void ++brcmf_cfg80211_event(struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data) ++{ ++ u32 event_type = be32_to_cpu(e->event_type); ++ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); ++ ++ if (!brcmf_enq_event(cfg_priv, event_type, e)) ++ schedule_work(&cfg_priv->event_work); ++} ++ ++static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) ++{ ++ s32 infra = 0; ++ s32 err = 0; ++ ++ switch (iftype) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ WL_ERR("type (%d) : currently we do not support this mode\n", ++ iftype); ++ err = -EINVAL; ++ return err; ++ case NL80211_IFTYPE_ADHOC: ++ infra = 0; ++ break; ++ case NL80211_IFTYPE_STATION: ++ infra = 1; ++ break; ++ default: ++ err = -EINVAL; ++ WL_ERR("invalid type (%d)\n", iftype); ++ return err; ++ } ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); ++ if (err) { ++ WL_ERR("WLC_SET_INFRA error (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static s32 brcmf_dongle_eventmsg(struct net_device *ndev) ++{ ++ /* Room for "event_msgs" + '\0' + bitvec */ ++ s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; ++ s8 eventmask[BRCMF_EVENTING_MASK_LEN]; ++ s32 err = 0; ++ ++ WL_TRACE("Enter\n"); ++ ++ /* Setup event_msgs */ ++ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); ++ if (err) { ++ WL_ERR("Get event_msgs error (%d)\n", err); ++ goto dongle_eventmsg_out; ++ } ++ memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); ++ ++ setbit(eventmask, BRCMF_E_SET_SSID); ++ setbit(eventmask, BRCMF_E_ROAM); ++ setbit(eventmask, BRCMF_E_PRUNE); ++ setbit(eventmask, BRCMF_E_AUTH); ++ setbit(eventmask, BRCMF_E_REASSOC); ++ setbit(eventmask, BRCMF_E_REASSOC_IND); ++ setbit(eventmask, BRCMF_E_DEAUTH_IND); ++ setbit(eventmask, BRCMF_E_DISASSOC_IND); ++ setbit(eventmask, BRCMF_E_DISASSOC); ++ setbit(eventmask, BRCMF_E_JOIN); ++ setbit(eventmask, BRCMF_E_ASSOC_IND); ++ setbit(eventmask, BRCMF_E_PSK_SUP); ++ setbit(eventmask, BRCMF_E_LINK); ++ setbit(eventmask, BRCMF_E_NDIS_LINK); ++ setbit(eventmask, BRCMF_E_MIC_ERROR); ++ setbit(eventmask, BRCMF_E_PMKID_CACHE); ++ setbit(eventmask, BRCMF_E_TXFAIL); ++ setbit(eventmask, BRCMF_E_JOIN_START); ++ setbit(eventmask, BRCMF_E_SCAN_COMPLETE); ++ ++ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); ++ if (err) { ++ WL_ERR("Set event_msgs error (%d)\n", err); ++ goto dongle_eventmsg_out; ++ } ++ ++dongle_eventmsg_out: ++ WL_TRACE("Exit\n"); ++ return err; ++} ++ ++static s32 ++brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) ++{ ++ s8 iovbuf[32]; ++ s32 err = 0; ++ __le32 roamtrigger[2]; ++ __le32 roam_delta[2]; ++ __le32 bcn_to_le; ++ __le32 roamvar_le; ++ ++ /* ++ * Setup timeout if Beacons are lost and roam is ++ * off to report link down ++ */ ++ if (roamvar) { ++ bcn_to_le = cpu_to_le32(bcn_timeout); ++ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le, ++ sizeof(bcn_to_le), iovbuf, sizeof(iovbuf)); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, ++ iovbuf, sizeof(iovbuf)); ++ if (err) { ++ WL_ERR("bcn_timeout error (%d)\n", err); ++ goto dongle_rom_out; ++ } ++ } ++ ++ /* ++ * Enable/Disable built-in roaming to allow supplicant ++ * to take care of roaming ++ */ ++ WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); ++ roamvar_le = cpu_to_le32(roamvar); ++ brcmf_c_mkiovar("roam_off", (char *)&roamvar_le, ++ sizeof(roamvar_le), iovbuf, sizeof(iovbuf)); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); ++ if (err) { ++ WL_ERR("roam_off error (%d)\n", err); ++ goto dongle_rom_out; ++ } ++ ++ roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL); ++ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER, ++ (void *)roamtrigger, sizeof(roamtrigger)); ++ if (err) { ++ WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err); ++ goto dongle_rom_out; ++ } ++ ++ roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA); ++ roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA, ++ (void *)roam_delta, sizeof(roam_delta)); ++ if (err) { ++ WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err); ++ goto dongle_rom_out; ++ } ++ ++dongle_rom_out: ++ return err; ++} ++ ++static s32 ++brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, ++ s32 scan_unassoc_time, s32 scan_passive_time) ++{ ++ s32 err = 0; ++ __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time); ++ __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time); ++ __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time); ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, ++ &scan_assoc_tm_le, sizeof(scan_assoc_tm_le)); ++ if (err) { ++ if (err == -EOPNOTSUPP) ++ WL_INFO("Scan assoc time is not supported\n"); ++ else ++ WL_ERR("Scan assoc time error (%d)\n", err); ++ goto dongle_scantime_out; ++ } ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, ++ &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le)); ++ if (err) { ++ if (err == -EOPNOTSUPP) ++ WL_INFO("Scan unassoc time is not supported\n"); ++ else ++ WL_ERR("Scan unassoc time error (%d)\n", err); ++ goto dongle_scantime_out; ++ } ++ ++ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, ++ &scan_passive_tm_le, sizeof(scan_passive_tm_le)); ++ if (err) { ++ if (err == -EOPNOTSUPP) ++ WL_INFO("Scan passive time is not supported\n"); ++ else ++ WL_ERR("Scan passive time error (%d)\n", err); ++ goto dongle_scantime_out; ++ } ++ ++dongle_scantime_out: ++ return err; ++} ++ ++static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct wiphy *wiphy; ++ s32 phy_list; ++ s8 phy; ++ s32 err = 0; ++ ++ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, ++ &phy_list, sizeof(phy_list)); ++ if (err) { ++ WL_ERR("error (%d)\n", err); ++ return err; ++ } ++ ++ phy = ((char *)&phy_list)[1]; ++ WL_INFO("%c phy\n", phy); ++ if (phy == 'n' || phy == 'a') { ++ wiphy = cfg_to_wiphy(cfg_priv); ++ wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; ++ } ++ ++ return err; ++} ++ ++static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ return wl_update_wiphybands(cfg_priv); ++} ++ ++static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ struct net_device *ndev; ++ struct wireless_dev *wdev; ++ s32 power_mode; ++ s32 err = 0; ++ ++ if (cfg_priv->dongle_up) ++ return err; ++ ++ ndev = cfg_to_ndev(cfg_priv); ++ wdev = ndev->ieee80211_ptr; ++ ++ brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, ++ WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); ++ ++ err = brcmf_dongle_eventmsg(ndev); ++ if (err) ++ goto default_conf_out; ++ ++ power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF; ++ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); ++ if (err) ++ goto default_conf_out; ++ WL_INFO("power save set to %s\n", ++ (power_mode ? "enabled" : "disabled")); ++ ++ err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1), ++ WL_BEACON_TIMEOUT); ++ if (err) ++ goto default_conf_out; ++ err = brcmf_dongle_mode(ndev, wdev->iftype); ++ if (err && err != -EINPROGRESS) ++ goto default_conf_out; ++ err = brcmf_dongle_probecap(cfg_priv); ++ if (err) ++ goto default_conf_out; ++ ++ /* -EINPROGRESS: Call commit handler */ ++ ++default_conf_out: ++ ++ cfg_priv->dongle_up = true; ++ ++ return err; ++ ++} ++ ++static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ char buf[10+IFNAMSIZ]; ++ struct dentry *fd; ++ s32 err = 0; ++ ++ sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); ++ cfg_priv->debugfsdir = debugfs_create_dir(buf, ++ cfg_to_wiphy(cfg_priv)->debugfsdir); ++ ++ fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, ++ (u16 *)&cfg_priv->profile->beacon_interval); ++ if (!fd) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, ++ (u8 *)&cfg_priv->profile->dtim_period); ++ if (!fd) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++err_out: ++ return err; ++} ++ ++static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ debugfs_remove_recursive(cfg_priv->debugfsdir); ++ cfg_priv->debugfsdir = NULL; ++} ++ ++static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ s32 err = 0; ++ ++ set_bit(WL_STATUS_READY, &cfg_priv->status); ++ ++ brcmf_debugfs_add_netdev_params(cfg_priv); ++ ++ err = brcmf_config_dongle(cfg_priv); ++ if (err) ++ return err; ++ ++ brcmf_invoke_iscan(cfg_priv); ++ ++ return err; ++} ++ ++static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) ++{ ++ /* ++ * While going down, if associated with AP disassociate ++ * from AP to save power ++ */ ++ if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || ++ test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && ++ test_bit(WL_STATUS_READY, &cfg_priv->status)) { ++ WL_INFO("Disassociating from AP"); ++ brcmf_link_down(cfg_priv); ++ ++ /* Make sure WPA_Supplicant receives all the event ++ generated due to DISASSOC call to the fw to keep ++ the state fw and WPA_Supplicant state consistent ++ */ ++ brcmf_delay(500); ++ } ++ ++ set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); ++ brcmf_term_iscan(cfg_priv); ++ if (cfg_priv->scan_request) { ++ cfg80211_scan_done(cfg_priv->scan_request, true); ++ /* May need to perform this to cover rmmod */ ++ /* wl_set_mpc(cfg_to_ndev(wl), 1); */ ++ cfg_priv->scan_request = NULL; ++ } ++ clear_bit(WL_STATUS_READY, &cfg_priv->status); ++ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); ++ clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); ++ ++ brcmf_debugfs_remove_netdev(cfg_priv); ++ ++ return 0; ++} ++ ++s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv; ++ s32 err = 0; ++ ++ cfg_priv = brcmf_priv_get(cfg_dev); ++ mutex_lock(&cfg_priv->usr_sync); ++ err = __brcmf_cfg80211_up(cfg_priv); ++ mutex_unlock(&cfg_priv->usr_sync); ++ ++ return err; ++} ++ ++s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) ++{ ++ struct brcmf_cfg80211_priv *cfg_priv; ++ s32 err = 0; ++ ++ cfg_priv = brcmf_priv_get(cfg_dev); ++ mutex_lock(&cfg_priv->usr_sync); ++ err = __brcmf_cfg80211_down(cfg_priv); ++ mutex_unlock(&cfg_priv->usr_sync); ++ ++ return err; ++} ++ ++static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, ++ u8 t, u8 l, u8 *v) ++{ ++ struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; ++ s32 err = 0; ++ ++ if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { ++ WL_ERR("ei crosses buffer boundary\n"); ++ return -ENOSPC; ++ } ++ ie->buf[ie->offset] = t; ++ ie->buf[ie->offset + 1] = l; ++ memcpy(&ie->buf[ie->offset + 2], v, l); ++ ie->offset += l + 2; ++ ++ return err; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h.orig 2011-11-09 13:46:58.238800722 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h 2011-11-09 13:47:16.989566304 -0500 +@@ -0,0 +1,375 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _wl_cfg80211_h_ ++#define _wl_cfg80211_h_ ++ ++struct brcmf_cfg80211_conf; ++struct brcmf_cfg80211_iface; ++struct brcmf_cfg80211_priv; ++struct brcmf_cfg80211_security; ++struct brcmf_cfg80211_ibss; ++ ++#define WL_DBG_NONE 0 ++#define WL_DBG_CONN (1 << 5) ++#define WL_DBG_SCAN (1 << 4) ++#define WL_DBG_TRACE (1 << 3) ++#define WL_DBG_INFO (1 << 1) ++#define WL_DBG_ERR (1 << 0) ++#define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \ ++ (WL_DBG_SCAN) | (WL_DBG_CONN)) ++ ++#define WL_ERR(fmt, args...) \ ++do { \ ++ if (brcmf_dbg_level & WL_DBG_ERR) { \ ++ if (net_ratelimit()) { \ ++ printk(KERN_ERR "ERROR @%s : " fmt, \ ++ __func__, ##args); \ ++ } \ ++ } \ ++} while (0) ++ ++#if (defined BCMDBG) ++#define WL_INFO(fmt, args...) \ ++do { \ ++ if (brcmf_dbg_level & WL_DBG_INFO) { \ ++ if (net_ratelimit()) { \ ++ printk(KERN_ERR "INFO @%s : " fmt, \ ++ __func__, ##args); \ ++ } \ ++ } \ ++} while (0) ++ ++#define WL_TRACE(fmt, args...) \ ++do { \ ++ if (brcmf_dbg_level & WL_DBG_TRACE) { \ ++ if (net_ratelimit()) { \ ++ printk(KERN_ERR "TRACE @%s : " fmt, \ ++ __func__, ##args); \ ++ } \ ++ } \ ++} while (0) ++ ++#define WL_SCAN(fmt, args...) \ ++do { \ ++ if (brcmf_dbg_level & WL_DBG_SCAN) { \ ++ if (net_ratelimit()) { \ ++ printk(KERN_ERR "SCAN @%s : " fmt, \ ++ __func__, ##args); \ ++ } \ ++ } \ ++} while (0) ++ ++#define WL_CONN(fmt, args...) \ ++do { \ ++ if (brcmf_dbg_level & WL_DBG_CONN) { \ ++ if (net_ratelimit()) { \ ++ printk(KERN_ERR "CONN @%s : " fmt, \ ++ __func__, ##args); \ ++ } \ ++ } \ ++} while (0) ++ ++#else /* (defined BCMDBG) */ ++#define WL_INFO(fmt, args...) ++#define WL_TRACE(fmt, args...) ++#define WL_SCAN(fmt, args...) ++#define WL_CONN(fmt, args...) ++#endif /* (defined BCMDBG) */ ++ ++#define WL_NUM_SCAN_MAX 1 ++#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used ++ * for 2.6.33 kernel ++ * or later ++ */ ++#define WL_SCAN_BUF_MAX (1024 * 8) ++#define WL_TLV_INFO_MAX 1024 ++#define WL_BSS_INFO_MAX 2048 ++#define WL_ASSOC_INFO_MAX 512 /* ++ * needs to grab assoc info from dongle to ++ * report it to cfg80211 through "connect" ++ * event ++ */ ++#define WL_DCMD_LEN_MAX 1024 ++#define WL_EXTRA_BUF_MAX 2048 ++#define WL_ISCAN_BUF_MAX 2048 /* ++ * the buf length can be BRCMF_DCMD_MAXLEN ++ * to reduce iteration ++ */ ++#define WL_ISCAN_TIMER_INTERVAL_MS 3000 ++#define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1) ++#define WL_AP_MAX 256 /* virtually unlimitted as long ++ * as kernel memory allows ++ */ ++ ++#define WL_ROAM_TRIGGER_LEVEL -75 ++#define WL_ROAM_DELTA 20 ++#define WL_BEACON_TIMEOUT 3 ++ ++#define WL_SCAN_CHANNEL_TIME 40 ++#define WL_SCAN_UNASSOC_TIME 40 ++#define WL_SCAN_PASSIVE_TIME 120 ++ ++/* dongle status */ ++enum wl_status { ++ WL_STATUS_READY, ++ WL_STATUS_SCANNING, ++ WL_STATUS_SCAN_ABORTING, ++ WL_STATUS_CONNECTING, ++ WL_STATUS_CONNECTED ++}; ++ ++/* wi-fi mode */ ++enum wl_mode { ++ WL_MODE_BSS, ++ WL_MODE_IBSS, ++ WL_MODE_AP ++}; ++ ++/* dongle profile list */ ++enum wl_prof_list { ++ WL_PROF_MODE, ++ WL_PROF_SSID, ++ WL_PROF_SEC, ++ WL_PROF_IBSS, ++ WL_PROF_BAND, ++ WL_PROF_BSSID, ++ WL_PROF_ACT, ++ WL_PROF_BEACONINT, ++ WL_PROF_DTIMPERIOD ++}; ++ ++/* dongle iscan state */ ++enum wl_iscan_state { ++ WL_ISCAN_STATE_IDLE, ++ WL_ISCAN_STATE_SCANING ++}; ++ ++/* dongle configuration */ ++struct brcmf_cfg80211_conf { ++ u32 mode; /* adhoc , infrastructure or ap */ ++ u32 frag_threshold; ++ u32 rts_threshold; ++ u32 retry_short; ++ u32 retry_long; ++ s32 tx_power; ++ struct ieee80211_channel channel; ++}; ++ ++/* cfg80211 main event loop */ ++struct brcmf_cfg80211_event_loop { ++ s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv, ++ struct net_device *ndev, ++ const struct brcmf_event_msg *e, ++ void *data); ++}; ++ ++/* representing interface of cfg80211 plane */ ++struct brcmf_cfg80211_iface { ++ struct brcmf_cfg80211_priv *cfg_priv; ++}; ++ ++struct brcmf_cfg80211_dev { ++ void *driver_data; /* to store cfg80211 object information */ ++}; ++ ++/* basic structure of scan request */ ++struct brcmf_cfg80211_scan_req { ++ struct brcmf_ssid_le ssid_le; ++}; ++ ++/* basic structure of information element */ ++struct brcmf_cfg80211_ie { ++ u16 offset; ++ u8 buf[WL_TLV_INFO_MAX]; ++}; ++ ++/* event queue for cfg80211 main event */ ++struct brcmf_cfg80211_event_q { ++ struct list_head evt_q_list; ++ u32 etype; ++ struct brcmf_event_msg emsg; ++ s8 edata[1]; ++}; ++ ++/* security information with currently associated ap */ ++struct brcmf_cfg80211_security { ++ u32 wpa_versions; ++ u32 auth_type; ++ u32 cipher_pairwise; ++ u32 cipher_group; ++ u32 wpa_auth; ++}; ++ ++/* ibss information for currently joined ibss network */ ++struct brcmf_cfg80211_ibss { ++ u8 beacon_interval; /* in millisecond */ ++ u8 atim; /* in millisecond */ ++ s8 join_only; ++ u8 band; ++ u8 channel; ++}; ++ ++/* dongle profile */ ++struct brcmf_cfg80211_profile { ++ u32 mode; ++ struct brcmf_ssid ssid; ++ u8 bssid[ETH_ALEN]; ++ u16 beacon_interval; ++ u8 dtim_period; ++ struct brcmf_cfg80211_security sec; ++ struct brcmf_cfg80211_ibss ibss; ++ s32 band; ++}; ++ ++/* dongle iscan event loop */ ++struct brcmf_cfg80211_iscan_eloop { ++ s32 (*handler[WL_SCAN_ERSULTS_LAST]) ++ (struct brcmf_cfg80211_priv *cfg_priv); ++}; ++ ++/* dongle iscan controller */ ++struct brcmf_cfg80211_iscan_ctrl { ++ struct net_device *ndev; ++ struct timer_list timer; ++ u32 timer_ms; ++ u32 timer_on; ++ s32 state; ++ struct work_struct work; ++ struct brcmf_cfg80211_iscan_eloop el; ++ void *data; ++ s8 dcmd_buf[BRCMF_DCMD_SMLEN]; ++ s8 scan_buf[WL_ISCAN_BUF_MAX]; ++}; ++ ++/* association inform */ ++struct brcmf_cfg80211_connect_info { ++ u8 *req_ie; ++ s32 req_ie_len; ++ u8 *resp_ie; ++ s32 resp_ie_len; ++}; ++ ++/* assoc ie length */ ++struct brcmf_cfg80211_assoc_ielen_le { ++ __le32 req_len; ++ __le32 resp_len; ++}; ++ ++/* wpa2 pmk list */ ++struct brcmf_cfg80211_pmk_list { ++ struct pmkid_list pmkids; ++ struct pmkid foo[MAXPMKID - 1]; ++}; ++ ++/* dongle private data of cfg80211 interface */ ++struct brcmf_cfg80211_priv { ++ struct wireless_dev *wdev; /* representing wl cfg80211 device */ ++ struct brcmf_cfg80211_conf *conf; /* dongle configuration */ ++ struct cfg80211_scan_request *scan_request; /* scan request ++ object */ ++ struct brcmf_cfg80211_event_loop el; /* main event loop */ ++ struct list_head evt_q_list; /* used for event queue */ ++ spinlock_t evt_q_lock; /* for event queue synchronization */ ++ struct mutex usr_sync; /* maily for dongle up/down synchronization */ ++ struct brcmf_scan_results *bss_list; /* bss_list holding scanned ++ ap information */ ++ struct brcmf_scan_results *scan_results; ++ struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object ++ for internal purpose */ ++ struct wl_cfg80211_bss_info *bss_info; /* bss information for ++ cfg80211 layer */ ++ struct brcmf_cfg80211_ie ie; /* information element object for ++ internal purpose */ ++ struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ ++ struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ ++ struct brcmf_cfg80211_connect_info conn_info; /* association info */ ++ struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ ++ struct work_struct event_work; /* event handler work struct */ ++ unsigned long status; /* current dongle status */ ++ void *pub; ++ u32 channel; /* current channel */ ++ bool iscan_on; /* iscan on/off switch */ ++ bool iscan_kickstart; /* indicate iscan already started */ ++ bool active_scan; /* current scan mode */ ++ bool ibss_starter; /* indicates this sta is ibss starter */ ++ bool link_up; /* link/connection up flag */ ++ bool pwr_save; /* indicate whether dongle to support ++ power save mode */ ++ bool dongle_up; /* indicate whether dongle up or not */ ++ bool roam_on; /* on/off switch for dongle self-roaming */ ++ bool scan_tried; /* indicates if first scan attempted */ ++ u8 *dcmd_buf; /* dcmd buffer */ ++ u8 *extra_buf; /* maily to grab assoc information */ ++ struct dentry *debugfsdir; ++ u8 ci[0] __aligned(NETDEV_ALIGN); ++}; ++ ++static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w) ++{ ++ return w->wdev->wiphy; ++} ++ ++static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w) ++{ ++ return (struct brcmf_cfg80211_priv *)(wiphy_priv(w)); ++} ++ ++static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd) ++{ ++ return (struct brcmf_cfg80211_priv *)(wdev_priv(wd)); ++} ++ ++static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg) ++{ ++ return cfg->wdev->netdev; ++} ++ ++static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev) ++{ ++ return wdev_to_cfg(ndev->ieee80211_ptr); ++} ++ ++#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data)) ++#define cfg_to_iscan(w) (w->iscan) ++ ++static inline struct ++brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) ++{ ++ return &cfg->conn_info; ++} ++ ++static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list, ++ struct brcmf_bss_info *bss) ++{ ++ return bss = bss ? ++ (struct brcmf_bss_info *)((unsigned long)bss + ++ le32_to_cpu(bss->length)) : ++ list->bss_info; ++} ++ ++extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, ++ struct device *busdev, ++ void *data); ++extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); ++ ++/* event handler from dongle */ ++extern void brcmf_cfg80211_event(struct net_device *ndev, ++ const struct brcmf_event_msg *e, void *data); ++extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev); ++extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev); ++ ++#endif /* _wl_cfg80211_h_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c.orig 2011-11-09 13:46:58.239800709 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c 2011-11-09 13:47:16.991566278 -0500 +@@ -0,0 +1,2079 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ * ++ * File contents: support functions for PCI/PCIe ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include "types.h" ++#include "pub.h" ++#include "pmu.h" ++#include "srom.h" ++#include "nicpci.h" ++#include "aiutils.h" ++ ++/* slow_clk_ctl */ ++ /* slow clock source mask */ ++#define SCC_SS_MASK 0x00000007 ++ /* source of slow clock is LPO */ ++#define SCC_SS_LPO 0x00000000 ++ /* source of slow clock is crystal */ ++#define SCC_SS_XTAL 0x00000001 ++ /* source of slow clock is PCI */ ++#define SCC_SS_PCI 0x00000002 ++ /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ ++#define SCC_LF 0x00000200 ++ /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ ++#define SCC_LP 0x00000400 ++ /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ ++#define SCC_FS 0x00000800 ++ /* IgnorePllOffReq, 1/0: ++ * power logic ignores/honors PLL clock disable requests from core ++ */ ++#define SCC_IP 0x00001000 ++ /* XtalControlEn, 1/0: ++ * power logic does/doesn't disable crystal when appropriate ++ */ ++#define SCC_XC 0x00002000 ++ /* XtalPU (RO), 1/0: crystal running/disabled */ ++#define SCC_XP 0x00004000 ++ /* ClockDivider (SlowClk = 1/(4+divisor)) */ ++#define SCC_CD_MASK 0xffff0000 ++#define SCC_CD_SHIFT 16 ++ ++/* system_clk_ctl */ ++ /* ILPen: Enable Idle Low Power */ ++#define SYCC_IE 0x00000001 ++ /* ALPen: Enable Active Low Power */ ++#define SYCC_AE 0x00000002 ++ /* ForcePLLOn */ ++#define SYCC_FP 0x00000004 ++ /* Force ALP (or HT if ALPen is not set */ ++#define SYCC_AR 0x00000008 ++ /* Force HT */ ++#define SYCC_HR 0x00000010 ++ /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ ++#define SYCC_CD_MASK 0xffff0000 ++#define SYCC_CD_SHIFT 16 ++ ++#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 ++ /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4329_DEFCIS_SEL 0 ++ /* OTP is powered up, SPROM is present */ ++#define CST4329_SPROM_SEL 1 ++ /* OTP is powered up, no SPROM */ ++#define CST4329_OTP_SEL 2 ++ /* OTP is powered down, SPROM is present */ ++#define CST4329_OTP_PWRDN 3 ++ ++#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 ++#define CST4329_SPI_SDIO_MODE_SHIFT 2 ++ ++/* 43224 chip-specific ChipControl register bits */ ++#define CCTRL43224_GPIO_TOGGLE 0x8000 ++ /* 12 mA drive strength */ ++#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 ++ /* 12 mA drive strength for later 43224s */ ++#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 ++ ++/* 43236 Chip specific ChipStatus register bits */ ++#define CST43236_SFLASH_MASK 0x00000040 ++#define CST43236_OTP_MASK 0x00000080 ++#define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ ++#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ ++#define CST43236_BOOT_MASK 0x00001800 ++#define CST43236_BOOT_SHIFT 11 ++#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST43236_BOOT_FROM_INVALID 3 ++ ++/* 4331 chip-specific ChipControl register bits */ ++ /* 0 disable */ ++#define CCTRL4331_BT_COEXIST (1<<0) ++ /* 0 SECI is disabled (JTAG functional) */ ++#define CCTRL4331_SECI (1<<1) ++ /* 0 disable */ ++#define CCTRL4331_EXT_LNA (1<<2) ++ /* sprom/gpio13-15 mux */ ++#define CCTRL4331_SPROM_GPIO13_15 (1<<3) ++ /* 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_EXTPA_EN (1<<4) ++ /* set drive out GPIO_CLK on sprom_cs pin */ ++#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) ++ /* use sprom_cs pin as PCIE mdio interface */ ++#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) ++ /* aband extpa will be at gpio2/5 and sprom_dout */ ++#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) ++ /* override core control on pipe_AuxClkEnable */ ++#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) ++ /* override core control on pipe_AuxPowerDown */ ++#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) ++ /* pcie_auxclkenable */ ++#define CCTRL4331_PCIE_AUXCLKEN (1<<10) ++ /* pcie_pipe_pllpowerdown */ ++#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) ++ /* enable bt_shd0 at gpio4 */ ++#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) ++ /* enable bt_shd1 at gpio5 */ ++#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) ++ ++/* 4331 Chip specific ChipStatus register bits */ ++ /* crystal frequency 20/40Mhz */ ++#define CST4331_XTAL_FREQ 0x00000001 ++#define CST4331_SPROM_PRESENT 0x00000002 ++#define CST4331_OTP_PRESENT 0x00000004 ++#define CST4331_LDO_RF 0x00000008 ++#define CST4331_LDO_PAR 0x00000010 ++ ++/* 4319 chip-specific ChipStatus register bits */ ++#define CST4319_SPI_CPULESSUSB 0x00000001 ++#define CST4319_SPI_CLK_POL 0x00000002 ++#define CST4319_SPI_CLK_PH 0x00000008 ++ /* gpio [7:6], SDIO CIS selection */ ++#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 ++#define CST4319_SPROM_OTP_SEL_SHIFT 6 ++ /* use default CIS, OTP is powered up */ ++#define CST4319_DEFCIS_SEL 0x00000000 ++ /* use SPROM, OTP is powered up */ ++#define CST4319_SPROM_SEL 0x00000040 ++ /* use OTP, OTP is powered up */ ++#define CST4319_OTP_SEL 0x00000080 ++ /* use SPROM, OTP is powered down */ ++#define CST4319_OTP_PWRDN 0x000000c0 ++ /* gpio [8], sdio/usb mode */ ++#define CST4319_SDIO_USB_MODE 0x00000100 ++#define CST4319_REMAP_SEL_MASK 0x00000600 ++#define CST4319_ILPDIV_EN 0x00000800 ++#define CST4319_XTAL_PD_POL 0x00001000 ++#define CST4319_LPO_SEL 0x00002000 ++#define CST4319_RES_INIT_MODE 0x0000c000 ++ /* PALDO is configured with external PNP */ ++#define CST4319_PALDO_EXTPNP 0x00010000 ++#define CST4319_CBUCK_MODE_MASK 0x00060000 ++#define CST4319_CBUCK_MODE_BURST 0x00020000 ++#define CST4319_CBUCK_MODE_LPBURST 0x00060000 ++#define CST4319_RCAL_VALID 0x01000000 ++#define CST4319_RCAL_VALUE_MASK 0x3e000000 ++#define CST4319_RCAL_VALUE_SHIFT 25 ++ ++/* 4336 chip-specific ChipStatus register bits */ ++#define CST4336_SPI_MODE_MASK 0x00000001 ++#define CST4336_SPROM_PRESENT 0x00000002 ++#define CST4336_OTP_PRESENT 0x00000004 ++#define CST4336_ARMREMAP_0 0x00000008 ++#define CST4336_ILPDIV_EN_MASK 0x00000010 ++#define CST4336_ILPDIV_EN_SHIFT 4 ++#define CST4336_XTAL_PD_POL_MASK 0x00000020 ++#define CST4336_XTAL_PD_POL_SHIFT 5 ++#define CST4336_LPO_SEL_MASK 0x00000040 ++#define CST4336_LPO_SEL_SHIFT 6 ++#define CST4336_RES_INIT_MODE_MASK 0x00000180 ++#define CST4336_RES_INIT_MODE_SHIFT 7 ++#define CST4336_CBUCK_MODE_MASK 0x00000600 ++#define CST4336_CBUCK_MODE_SHIFT 9 ++ ++/* 4313 chip-specific ChipStatus register bits */ ++#define CST4313_SPROM_PRESENT 1 ++#define CST4313_OTP_PRESENT 2 ++#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 ++#define CST4313_SPROM_OTP_SEL_SHIFT 0 ++ ++/* 4313 Chip specific ChipControl register bits */ ++ /* 12 mA drive strengh for later 4313 */ ++#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 ++ ++/* Manufacturer Ids */ ++#define MFGID_ARM 0x43b ++#define MFGID_BRCM 0x4bf ++#define MFGID_MIPS 0x4a7 ++ ++/* Enumeration ROM registers */ ++#define ER_EROMENTRY 0x000 ++#define ER_REMAPCONTROL 0xe00 ++#define ER_REMAPSELECT 0xe04 ++#define ER_MASTERSELECT 0xe10 ++#define ER_ITCR 0xf00 ++#define ER_ITIP 0xf04 ++ ++/* Erom entries */ ++#define ER_TAG 0xe ++#define ER_TAG1 0x6 ++#define ER_VALID 1 ++#define ER_CI 0 ++#define ER_MP 2 ++#define ER_ADD 4 ++#define ER_END 0xe ++#define ER_BAD 0xffffffff ++ ++/* EROM CompIdentA */ ++#define CIA_MFG_MASK 0xfff00000 ++#define CIA_MFG_SHIFT 20 ++#define CIA_CID_MASK 0x000fff00 ++#define CIA_CID_SHIFT 8 ++#define CIA_CCL_MASK 0x000000f0 ++#define CIA_CCL_SHIFT 4 ++ ++/* EROM CompIdentB */ ++#define CIB_REV_MASK 0xff000000 ++#define CIB_REV_SHIFT 24 ++#define CIB_NSW_MASK 0x00f80000 ++#define CIB_NSW_SHIFT 19 ++#define CIB_NMW_MASK 0x0007c000 ++#define CIB_NMW_SHIFT 14 ++#define CIB_NSP_MASK 0x00003e00 ++#define CIB_NSP_SHIFT 9 ++#define CIB_NMP_MASK 0x000001f0 ++#define CIB_NMP_SHIFT 4 ++ ++/* EROM AddrDesc */ ++#define AD_ADDR_MASK 0xfffff000 ++#define AD_SP_MASK 0x00000f00 ++#define AD_SP_SHIFT 8 ++#define AD_ST_MASK 0x000000c0 ++#define AD_ST_SHIFT 6 ++#define AD_ST_SLAVE 0x00000000 ++#define AD_ST_BRIDGE 0x00000040 ++#define AD_ST_SWRAP 0x00000080 ++#define AD_ST_MWRAP 0x000000c0 ++#define AD_SZ_MASK 0x00000030 ++#define AD_SZ_SHIFT 4 ++#define AD_SZ_4K 0x00000000 ++#define AD_SZ_8K 0x00000010 ++#define AD_SZ_16K 0x00000020 ++#define AD_SZ_SZD 0x00000030 ++#define AD_AG32 0x00000008 ++#define AD_ADDR_ALIGN 0x00000fff ++#define AD_SZ_BASE 0x00001000 /* 4KB */ ++ ++/* EROM SizeDesc */ ++#define SD_SZ_MASK 0xfffff000 ++#define SD_SG32 0x00000008 ++#define SD_SZ_ALIGN 0x00000fff ++ ++/* PCI config space bit 4 for 4306c0 slow clock source */ ++#define PCI_CFG_GPIO_SCS 0x10 ++/* PCI config space GPIO 14 for Xtal power-up */ ++#define PCI_CFG_GPIO_XTAL 0x40 ++/* PCI config space GPIO 15 for PLL power-down */ ++#define PCI_CFG_GPIO_PLL 0x80 ++ ++/* power control defines */ ++#define PLL_DELAY 150 /* us pll on delay */ ++#define FREF_DELAY 200 /* us fref change delay */ ++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ ++ ++/* resetctrl */ ++#define AIRC_RESET 1 ++ ++#define NOREV -1 /* Invalid rev */ ++ ++/* GPIO Based LED powersave defines */ ++#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ ++#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ ++ ++/* When Srom support present, fields in sromcontrol */ ++#define SRC_START 0x80000000 ++#define SRC_BUSY 0x80000000 ++#define SRC_OPCODE 0x60000000 ++#define SRC_OP_READ 0x00000000 ++#define SRC_OP_WRITE 0x20000000 ++#define SRC_OP_WRDIS 0x40000000 ++#define SRC_OP_WREN 0x60000000 ++#define SRC_OTPSEL 0x00000010 ++#define SRC_LOCK 0x00000008 ++#define SRC_SIZE_MASK 0x00000006 ++#define SRC_SIZE_1K 0x00000000 ++#define SRC_SIZE_4K 0x00000002 ++#define SRC_SIZE_16K 0x00000004 ++#define SRC_SIZE_SHIFT 1 ++#define SRC_PRESENT 0x00000001 ++ ++/* External PA enable mask */ ++#define GPIO_CTRL_EPA_EN_MASK 0x40 ++ ++#define DEFAULT_GPIOTIMERVAL \ ++ ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) ++ ++#define BADIDX (SI_MAXCORES + 1) ++ ++/* Newer chips can access PCI/PCIE and CC core without requiring to change ++ * PCI BAR0 WIN ++ */ ++#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \ ++ (((si)->pub.buscoretype == PCI_CORE_ID) && \ ++ (si)->pub.buscorerev >= 13)) ++ ++#define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \ ++ PCI_16KB0_CCREGS_OFFSET)) ++ ++#define IS_SIM(chippkg) \ ++ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) ++ ++/* ++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts ++ * before after core switching to avoid invalid register accesss inside ISR. ++ */ ++#define INTR_OFF(si, intr_val) \ ++ if ((si)->intrsoff_fn && \ ++ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ ++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg) ++ ++#define INTR_RESTORE(si, intr_val) \ ++ if ((si)->intrsrestore_fn && \ ++ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ ++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val) ++ ++#define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID) ++#define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID) ++ ++#define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)) ++ ++#ifdef BCMDBG ++#define SI_MSG(args) printk args ++#else ++#define SI_MSG(args) ++#endif /* BCMDBG */ ++ ++#define GOODCOREADDR(x, b) \ ++ (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ ++ IS_ALIGNED((x), SI_CORE_SIZE)) ++ ++#define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \ ++ PCI_16KB0_PCIREGS_OFFSET) ++ ++struct aidmp { ++ u32 oobselina30; /* 0x000 */ ++ u32 oobselina74; /* 0x004 */ ++ u32 PAD[6]; ++ u32 oobselinb30; /* 0x020 */ ++ u32 oobselinb74; /* 0x024 */ ++ u32 PAD[6]; ++ u32 oobselinc30; /* 0x040 */ ++ u32 oobselinc74; /* 0x044 */ ++ u32 PAD[6]; ++ u32 oobselind30; /* 0x060 */ ++ u32 oobselind74; /* 0x064 */ ++ u32 PAD[38]; ++ u32 oobselouta30; /* 0x100 */ ++ u32 oobselouta74; /* 0x104 */ ++ u32 PAD[6]; ++ u32 oobseloutb30; /* 0x120 */ ++ u32 oobseloutb74; /* 0x124 */ ++ u32 PAD[6]; ++ u32 oobseloutc30; /* 0x140 */ ++ u32 oobseloutc74; /* 0x144 */ ++ u32 PAD[6]; ++ u32 oobseloutd30; /* 0x160 */ ++ u32 oobseloutd74; /* 0x164 */ ++ u32 PAD[38]; ++ u32 oobsynca; /* 0x200 */ ++ u32 oobseloutaen; /* 0x204 */ ++ u32 PAD[6]; ++ u32 oobsyncb; /* 0x220 */ ++ u32 oobseloutben; /* 0x224 */ ++ u32 PAD[6]; ++ u32 oobsyncc; /* 0x240 */ ++ u32 oobseloutcen; /* 0x244 */ ++ u32 PAD[6]; ++ u32 oobsyncd; /* 0x260 */ ++ u32 oobseloutden; /* 0x264 */ ++ u32 PAD[38]; ++ u32 oobaextwidth; /* 0x300 */ ++ u32 oobainwidth; /* 0x304 */ ++ u32 oobaoutwidth; /* 0x308 */ ++ u32 PAD[5]; ++ u32 oobbextwidth; /* 0x320 */ ++ u32 oobbinwidth; /* 0x324 */ ++ u32 oobboutwidth; /* 0x328 */ ++ u32 PAD[5]; ++ u32 oobcextwidth; /* 0x340 */ ++ u32 oobcinwidth; /* 0x344 */ ++ u32 oobcoutwidth; /* 0x348 */ ++ u32 PAD[5]; ++ u32 oobdextwidth; /* 0x360 */ ++ u32 oobdinwidth; /* 0x364 */ ++ u32 oobdoutwidth; /* 0x368 */ ++ u32 PAD[37]; ++ u32 ioctrlset; /* 0x400 */ ++ u32 ioctrlclear; /* 0x404 */ ++ u32 ioctrl; /* 0x408 */ ++ u32 PAD[61]; ++ u32 iostatus; /* 0x500 */ ++ u32 PAD[127]; ++ u32 ioctrlwidth; /* 0x700 */ ++ u32 iostatuswidth; /* 0x704 */ ++ u32 PAD[62]; ++ u32 resetctrl; /* 0x800 */ ++ u32 resetstatus; /* 0x804 */ ++ u32 resetreadid; /* 0x808 */ ++ u32 resetwriteid; /* 0x80c */ ++ u32 PAD[60]; ++ u32 errlogctrl; /* 0x900 */ ++ u32 errlogdone; /* 0x904 */ ++ u32 errlogstatus; /* 0x908 */ ++ u32 errlogaddrlo; /* 0x90c */ ++ u32 errlogaddrhi; /* 0x910 */ ++ u32 errlogid; /* 0x914 */ ++ u32 errloguser; /* 0x918 */ ++ u32 errlogflags; /* 0x91c */ ++ u32 PAD[56]; ++ u32 intstatus; /* 0xa00 */ ++ u32 PAD[127]; ++ u32 config; /* 0xe00 */ ++ u32 PAD[63]; ++ u32 itcr; /* 0xf00 */ ++ u32 PAD[3]; ++ u32 itipooba; /* 0xf10 */ ++ u32 itipoobb; /* 0xf14 */ ++ u32 itipoobc; /* 0xf18 */ ++ u32 itipoobd; /* 0xf1c */ ++ u32 PAD[4]; ++ u32 itipoobaout; /* 0xf30 */ ++ u32 itipoobbout; /* 0xf34 */ ++ u32 itipoobcout; /* 0xf38 */ ++ u32 itipoobdout; /* 0xf3c */ ++ u32 PAD[4]; ++ u32 itopooba; /* 0xf50 */ ++ u32 itopoobb; /* 0xf54 */ ++ u32 itopoobc; /* 0xf58 */ ++ u32 itopoobd; /* 0xf5c */ ++ u32 PAD[4]; ++ u32 itopoobain; /* 0xf70 */ ++ u32 itopoobbin; /* 0xf74 */ ++ u32 itopoobcin; /* 0xf78 */ ++ u32 itopoobdin; /* 0xf7c */ ++ u32 PAD[4]; ++ u32 itopreset; /* 0xf90 */ ++ u32 PAD[15]; ++ u32 peripherialid4; /* 0xfd0 */ ++ u32 peripherialid5; /* 0xfd4 */ ++ u32 peripherialid6; /* 0xfd8 */ ++ u32 peripherialid7; /* 0xfdc */ ++ u32 peripherialid0; /* 0xfe0 */ ++ u32 peripherialid1; /* 0xfe4 */ ++ u32 peripherialid2; /* 0xfe8 */ ++ u32 peripherialid3; /* 0xfec */ ++ u32 componentid0; /* 0xff0 */ ++ u32 componentid1; /* 0xff4 */ ++ u32 componentid2; /* 0xff8 */ ++ u32 componentid3; /* 0xffc */ ++}; ++ ++/* EROM parsing */ ++ ++static u32 ++get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match) ++{ ++ u32 ent; ++ uint inv = 0, nom = 0; ++ ++ while (true) { ++ ent = R_REG(*eromptr); ++ (*eromptr)++; ++ ++ if (mask == 0) ++ break; ++ ++ if ((ent & ER_VALID) == 0) { ++ inv++; ++ continue; ++ } ++ ++ if (ent == (ER_END | ER_VALID)) ++ break; ++ ++ if ((ent & mask) == match) ++ break; ++ ++ nom++; ++ } ++ ++ return ent; ++} ++ ++static u32 ++get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st, ++ u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh) ++{ ++ u32 asd, sz, szd; ++ ++ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); ++ if (((asd & ER_TAG1) != ER_ADD) || ++ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ++ ((asd & AD_ST_MASK) != st)) { ++ /* This is not what we want, "push" it back */ ++ (*eromptr)--; ++ return 0; ++ } ++ *addrl = asd & AD_ADDR_MASK; ++ if (asd & AD_AG32) ++ *addrh = get_erom_ent(sih, eromptr, 0, 0); ++ else ++ *addrh = 0; ++ *sizeh = 0; ++ sz = asd & AD_SZ_MASK; ++ if (sz == AD_SZ_SZD) { ++ szd = get_erom_ent(sih, eromptr, 0, 0); ++ *sizel = szd & SD_SZ_MASK; ++ if (szd & SD_SG32) ++ *sizeh = get_erom_ent(sih, eromptr, 0, 0); ++ } else ++ *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); ++ ++ return asd; ++} ++ ++static void ai_hwfixup(struct si_info *sii) ++{ ++} ++ ++/* parse the enumeration rom to identify all cores */ ++static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc) ++{ ++ struct si_info *sii = (struct si_info *)sih; ++ ++ u32 erombase; ++ u32 __iomem *eromptr, *eromlim; ++ void __iomem *regs = cc; ++ ++ erombase = R_REG(&cc->eromptr); ++ ++ /* Set wrappers address */ ++ sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE); ++ ++ /* Now point the window at the erom */ ++ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase); ++ eromptr = regs; ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32)); ++ ++ while (eromptr < eromlim) { ++ u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; ++ u32 mpd, asd, addrl, addrh, sizel, sizeh; ++ u32 __iomem *base; ++ uint i, j, idx; ++ bool br; ++ ++ br = false; ++ ++ /* Grok a component */ ++ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); ++ if (cia == (ER_END | ER_VALID)) { ++ /* Found END of erom */ ++ ai_hwfixup(sii); ++ return; ++ } ++ base = eromptr - 1; ++ cib = get_erom_ent(sih, &eromptr, 0, 0); ++ ++ if ((cib & ER_TAG) != ER_CI) { ++ /* CIA not followed by CIB */ ++ goto error; ++ } ++ ++ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; ++ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; ++ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; ++ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; ++ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) ++ continue; ++ if ((nmw + nsw == 0)) { ++ /* A component which is not a core */ ++ if (cid == OOB_ROUTER_CORE_ID) { ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, ++ &addrl, &addrh, &sizel, &sizeh); ++ if (asd != 0) ++ sii->oob_router = addrl; ++ } ++ continue; ++ } ++ ++ idx = sii->numcores; ++/* sii->eromptr[idx] = base; */ ++ sii->cia[idx] = cia; ++ sii->cib[idx] = cib; ++ sii->coreid[idx] = cid; ++ ++ for (i = 0; i < nmp; i++) { ++ mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ if ((mpd & ER_TAG) != ER_MP) { ++ /* Not enough MP entries for component */ ++ goto error; ++ } ++ } ++ ++ /* First Slave Address Descriptor should be port 0: ++ * the main register space for the core ++ */ ++ asd = ++ get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) { ++ /* Try again to see if it is a bridge */ ++ asd = ++ get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, ++ &addrh, &sizel, &sizeh); ++ if (asd != 0) ++ br = true; ++ else if ((addrh != 0) || (sizeh != 0) ++ || (sizel != SI_CORE_SIZE)) { ++ /* First Slave ASD for core malformed */ ++ goto error; ++ } ++ } ++ sii->coresba[idx] = addrl; ++ sii->coresba_size[idx] = sizel; ++ /* Get any more ASDs in port 0 */ ++ j = 1; ++ do { ++ asd = ++ get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, ++ &addrh, &sizel, &sizeh); ++ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { ++ sii->coresba2[idx] = addrl; ++ sii->coresba2_size[idx] = sizel; ++ } ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = ++ get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, ++ &addrl, &addrh, &sizel, &sizeh); ++ } while (asd != 0); ++ if (j == 0) { ++ /* SP has no address descriptors */ ++ goto error; ++ } ++ } ++ ++ /* Now get master wrappers */ ++ for (i = 0; i < nmw; i++) { ++ asd = ++ get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, ++ &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ /* Missing descriptor for MW */ ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ /* Master wrapper %d is not 4KB */ ++ goto error; ++ } ++ if (i == 0) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ /* And finally slave wrappers */ ++ for (i = 0; i < nsw; i++) { ++ uint fwp = (nsp == 1) ? 0 : 1; ++ asd = ++ get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, ++ &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ /* Missing descriptor for SW */ ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ /* Slave wrapper is not 4KB */ ++ goto error; ++ } ++ if ((nmw == 0) && (i == 0)) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ /* Don't record bridges */ ++ if (br) ++ continue; ++ ++ /* Done with core */ ++ sii->numcores++; ++ } ++ ++ error: ++ /* Reached end of erom without finding END */ ++ sii->numcores = 0; ++ return; ++} ++ ++/* ++ * This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. Since each core starts with the ++ * same set of registers (BIST, clock control, etc), the returned address ++ * contains the first register of this 'common' register block (not to be ++ * confused with 'common core'). ++ */ ++void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx) ++{ ++ struct si_info *sii = (struct si_info *)sih; ++ u32 addr = sii->coresba[coreidx]; ++ u32 wrap = sii->wrapba[coreidx]; ++ ++ if (coreidx >= sii->numcores) ++ return NULL; ++ ++ /* point bar0 window */ ++ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr); ++ /* point bar0 2nd 4KB window */ ++ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap); ++ sii->curidx = coreidx; ++ ++ return sii->curmap; ++} ++ ++/* Return the number of address spaces in current core */ ++int ai_numaddrspaces(struct si_pub *sih) ++{ ++ return 2; ++} ++ ++/* Return the address of the nth address space in the current core */ ++u32 ai_addrspace(struct si_pub *sih, uint asidx) ++{ ++ struct si_info *sii; ++ uint cidx; ++ ++ sii = (struct si_info *)sih; ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2[cidx]; ++ else { ++ /* Need to parse the erom again to find addr space */ ++ return 0; ++ } ++} ++ ++/* Return the size of the nth address space in the current core */ ++u32 ai_addrspacesize(struct si_pub *sih, uint asidx) ++{ ++ struct si_info *sii; ++ uint cidx; ++ ++ sii = (struct si_info *)sih; ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba_size[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2_size[cidx]; ++ else { ++ /* Need to parse the erom again to find addr */ ++ return 0; ++ } ++} ++ ++uint ai_flag(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ ++ sii = (struct si_info *)sih; ++ ai = sii->curwrap; ++ ++ return R_REG(&ai->oobselouta30) & 0x1f; ++} ++ ++void ai_setint(struct si_pub *sih, int siflag) ++{ ++} ++ ++uint ai_corevendor(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ u32 cia; ++ ++ sii = (struct si_info *)sih; ++ cia = sii->cia[sii->curidx]; ++ return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; ++} ++ ++uint ai_corerev(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ u32 cib; ++ ++ sii = (struct si_info *)sih; ++ cib = sii->cib[sii->curidx]; ++ return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; ++} ++ ++bool ai_iscoreup(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ ++ sii = (struct si_info *)sih; ++ ai = sii->curwrap; ++ ++ return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == ++ SICF_CLOCK_EN) ++ && ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0)); ++} ++ ++void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ u32 w; ++ ++ sii = (struct si_info *)sih; ++ ++ ai = sii->curwrap; ++ ++ if (mask || val) { ++ w = ((R_REG(&ai->ioctrl) & ~mask) | val); ++ W_REG(&ai->ioctrl, w); ++ } ++} ++ ++u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ u32 w; ++ ++ sii = (struct si_info *)sih; ++ ai = sii->curwrap; ++ ++ if (mask || val) { ++ w = ((R_REG(&ai->ioctrl) & ~mask) | val); ++ W_REG(&ai->ioctrl, w); ++ } ++ ++ return R_REG(&ai->ioctrl); ++} ++ ++/* return true if PCIE capability exists in the pci config space */ ++static bool ai_ispcie(struct si_info *sii) ++{ ++ u8 cap_ptr; ++ ++ cap_ptr = ++ pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL, ++ NULL); ++ if (!cap_ptr) ++ return false; ++ ++ return true; ++} ++ ++static bool ai_buscore_prep(struct si_info *sii) ++{ ++ /* kludge to enable the clock on the 4306 which lacks a slowclock */ ++ if (!ai_ispcie(sii)) ++ ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON); ++ return true; ++} ++ ++u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ u32 w; ++ ++ sii = (struct si_info *)sih; ++ ai = sii->curwrap; ++ ++ if (mask || val) { ++ w = ((R_REG(&ai->iostatus) & ~mask) | val); ++ W_REG(&ai->iostatus, w); ++ } ++ ++ return R_REG(&ai->iostatus); ++} ++ ++static bool ++ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx) ++{ ++ bool pci, pcie; ++ uint i; ++ uint pciidx, pcieidx, pcirev, pcierev; ++ struct chipcregs __iomem *cc; ++ ++ cc = ai_setcoreidx(&sii->pub, SI_CC_IDX); ++ ++ /* get chipcommon rev */ ++ sii->pub.ccrev = (int)ai_corerev(&sii->pub); ++ ++ /* get chipcommon chipstatus */ ++ if (sii->pub.ccrev >= 11) ++ sii->pub.chipst = R_REG(&cc->chipstatus); ++ ++ /* get chipcommon capabilites */ ++ sii->pub.cccaps = R_REG(&cc->capabilities); ++ /* get chipcommon extended capabilities */ ++ ++ if (sii->pub.ccrev >= 35) ++ sii->pub.cccaps_ext = R_REG(&cc->capabilities_ext); ++ ++ /* get pmu rev and caps */ ++ if (sii->pub.cccaps & CC_CAP_PMU) { ++ sii->pub.pmucaps = R_REG(&cc->pmucapabilities); ++ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; ++ } ++ ++ /* figure out bus/orignal core idx */ ++ sii->pub.buscoretype = NODEV_CORE_ID; ++ sii->pub.buscorerev = NOREV; ++ sii->pub.buscoreidx = BADIDX; ++ ++ pci = pcie = false; ++ pcirev = pcierev = NOREV; ++ pciidx = pcieidx = BADIDX; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ uint cid, crev; ++ ++ ai_setcoreidx(&sii->pub, i); ++ cid = ai_coreid(&sii->pub); ++ crev = ai_corerev(&sii->pub); ++ ++ if (cid == PCI_CORE_ID) { ++ pciidx = i; ++ pcirev = crev; ++ pci = true; ++ } else if (cid == PCIE_CORE_ID) { ++ pcieidx = i; ++ pcierev = crev; ++ pcie = true; ++ } ++ ++ /* find the core idx before entering this func. */ ++ if ((savewin && (savewin == sii->coresba[i])) || ++ (cc == sii->regs[i])) ++ *origidx = i; ++ } ++ ++ if (pci && pcie) { ++ if (ai_ispcie(sii)) ++ pci = false; ++ else ++ pcie = false; ++ } ++ if (pci) { ++ sii->pub.buscoretype = PCI_CORE_ID; ++ sii->pub.buscorerev = pcirev; ++ sii->pub.buscoreidx = pciidx; ++ } else if (pcie) { ++ sii->pub.buscoretype = PCIE_CORE_ID; ++ sii->pub.buscorerev = pcierev; ++ sii->pub.buscoreidx = pcieidx; ++ } ++ ++ /* fixup necessary chip/core configurations */ ++ if (SI_FAST(sii)) { ++ if (!sii->pch) { ++ sii->pch = pcicore_init(&sii->pub, sii->pbus, ++ (__iomem void *)PCIEREGS(sii)); ++ if (sii->pch == NULL) ++ return false; ++ } ++ } ++ if (ai_pci_fixcfg(&sii->pub)) { ++ /* si_doattach: si_pci_fixcfg failed */ ++ return false; ++ } ++ ++ /* return to the original core */ ++ ai_setcoreidx(&sii->pub, *origidx); ++ ++ return true; ++} ++ ++/* ++ * get boardtype and boardrev ++ */ ++static __used void ai_nvram_process(struct si_info *sii) ++{ ++ uint w = 0; ++ ++ /* do a pci config read to get subsystem id and subvendor id */ ++ pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w); ++ ++ sii->pub.boardvendor = w & 0xffff; ++ sii->pub.boardtype = (w >> 16) & 0xffff; ++ sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS); ++} ++ ++static struct si_info *ai_doattach(struct si_info *sii, ++ void __iomem *regs, struct pci_dev *pbus) ++{ ++ struct si_pub *sih = &sii->pub; ++ u32 w, savewin; ++ struct chipcregs __iomem *cc; ++ uint socitype; ++ uint origidx; ++ ++ memset((unsigned char *) sii, 0, sizeof(struct si_info)); ++ ++ savewin = 0; ++ ++ sih->buscoreidx = BADIDX; ++ ++ sii->curmap = regs; ++ sii->pbus = pbus; ++ ++ /* find Chipcommon address */ ++ pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin); ++ if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) ++ savewin = SI_ENUM_BASE; ++ ++ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, ++ SI_ENUM_BASE); ++ cc = (struct chipcregs __iomem *) regs; ++ ++ /* bus/core/clk setup for register access */ ++ if (!ai_buscore_prep(sii)) ++ return NULL; ++ ++ /* ++ * ChipID recognition. ++ * We assume we can read chipid at offset 0 from the regs arg. ++ * If we add other chiptypes (or if we need to support old sdio ++ * hosts w/o chipcommon), some way of recognizing them needs to ++ * be added here. ++ */ ++ w = R_REG(&cc->chipid); ++ socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; ++ /* Might as wll fill in chip id rev & pkg */ ++ sih->chip = w & CID_ID_MASK; ++ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; ++ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; ++ ++ sih->issim = false; ++ ++ /* scan for cores */ ++ if (socitype == SOCI_AI) { ++ SI_MSG(("Found chip type AI (0x%08x)\n", w)); ++ /* pass chipc address instead of original core base */ ++ ai_scan(&sii->pub, cc); ++ } else { ++ /* Found chip of unknown type */ ++ return NULL; ++ } ++ /* no cores found, bail out */ ++ if (sii->numcores == 0) ++ return NULL; ++ ++ /* bus/core/clk setup */ ++ origidx = SI_CC_IDX; ++ if (!ai_buscore_setup(sii, savewin, &origidx)) ++ goto exit; ++ ++ /* Init nvram from sprom/otp if they exist */ ++ if (srom_var_init(&sii->pub, cc)) ++ goto exit; ++ ++ ai_nvram_process(sii); ++ ++ /* === NVRAM, clock is ready === */ ++ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); ++ W_REG(&cc->gpiopullup, 0); ++ W_REG(&cc->gpiopulldown, 0); ++ ai_setcoreidx(sih, origidx); ++ ++ /* PMU specific initializations */ ++ if (sih->cccaps & CC_CAP_PMU) { ++ u32 xtalfreq; ++ si_pmu_init(sih); ++ si_pmu_chip_init(sih); ++ ++ xtalfreq = si_pmu_measure_alpclk(sih); ++ si_pmu_pll_init(sih, xtalfreq); ++ si_pmu_res_init(sih); ++ si_pmu_swreg_init(sih); ++ } ++ ++ /* setup the GPIO based LED powersave register */ ++ w = getintvar(sih, BRCMS_SROM_LEDDC); ++ if (w == 0) ++ w = DEFAULT_GPIOTIMERVAL; ++ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval), ++ ~0, w); ++ ++ if (PCIE(sii)) ++ pcicore_attach(sii->pch, SI_DOATTACH); ++ ++ if (sih->chip == BCM43224_CHIP_ID) { ++ /* ++ * enable 12 mA drive strenth for 43224 and ++ * set chipControl register bit 15 ++ */ ++ if (sih->chiprev == 0) { ++ SI_MSG(("Applying 43224A0 WARs\n")); ++ ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol), ++ CCTRL43224_GPIO_TOGGLE, ++ CCTRL43224_GPIO_TOGGLE); ++ si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, ++ CCTRL_43224A0_12MA_LED_DRIVE); ++ } ++ if (sih->chiprev >= 1) { ++ SI_MSG(("Applying 43224B0+ WARs\n")); ++ si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, ++ CCTRL_43224B0_12MA_LED_DRIVE); ++ } ++ } ++ ++ if (sih->chip == BCM4313_CHIP_ID) { ++ /* ++ * enable 12 mA drive strenth for 4313 and ++ * set chipControl register bit 1 ++ */ ++ SI_MSG(("Applying 4313 WARs\n")); ++ si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, ++ CCTRL_4313_12MA_LED_DRIVE); ++ } ++ ++ return sii; ++ ++ exit: ++ if (sii->pch) ++ pcicore_deinit(sii->pch); ++ sii->pch = NULL; ++ ++ return NULL; ++} ++ ++/* ++ * Allocate a si handle. ++ * devid - pci device id (used to determine chip#) ++ * osh - opaque OS handle ++ * regs - virtual address of initial core registers ++ */ ++struct si_pub * ++ai_attach(void __iomem *regs, struct pci_dev *sdh) ++{ ++ struct si_info *sii; ++ ++ /* alloc struct si_info */ ++ sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC); ++ if (sii == NULL) ++ return NULL; ++ ++ if (ai_doattach(sii, regs, sdh) == NULL) { ++ kfree(sii); ++ return NULL; ++ } ++ ++ return (struct si_pub *) sii; ++} ++ ++/* may be called with core in reset */ ++void ai_detach(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ struct si_pub *si_local = NULL; ++ memcpy(&si_local, &sih, sizeof(struct si_pub **)); ++ ++ sii = (struct si_info *)sih; ++ ++ if (sii == NULL) ++ return; ++ ++ if (sii->pch) ++ pcicore_deinit(sii->pch); ++ sii->pch = NULL; ++ ++ srom_free_vars(sih); ++ kfree(sii); ++} ++ ++/* register driver interrupt disabling and restoring callback functions */ ++void ++ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, ++ void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ sii->intr_arg = intr_arg; ++ sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn; ++ sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn; ++ sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn; ++ /* save current core id. when this function called, the current core ++ * must be the core which provides driver functions(il, et, wl, etc.) ++ */ ++ sii->dev_coreid = sii->coreid[sii->curidx]; ++} ++ ++void ai_deregister_intr_callback(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ sii->intrsoff_fn = NULL; ++} ++ ++uint ai_coreid(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ return sii->coreid[sii->curidx]; ++} ++ ++uint ai_coreidx(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ return sii->curidx; ++} ++ ++bool ai_backplane64(struct si_pub *sih) ++{ ++ return (sih->cccaps & CC_CAP_BKPLN64) != 0; ++} ++ ++/* return index of coreid or BADIDX if not found */ ++uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit) ++{ ++ struct si_info *sii; ++ uint found; ++ uint i; ++ ++ sii = (struct si_info *)sih; ++ ++ found = 0; ++ ++ for (i = 0; i < sii->numcores; i++) ++ if (sii->coreid[i] == coreid) { ++ if (found == coreunit) ++ return i; ++ found++; ++ } ++ ++ return BADIDX; ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching ++ * out of and back to d11 core. ++ */ ++void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit) ++{ ++ uint idx; ++ ++ idx = ai_findcoreidx(sih, coreid, coreunit); ++ if (idx >= SI_MAXCORES) ++ return NULL; ++ ++ return ai_setcoreidx(sih, idx); ++} ++ ++/* Turn off interrupt as required by ai_setcore, before switch core */ ++void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx, ++ uint *intr_val) ++{ ++ void __iomem *cc; ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ if (SI_FAST(sii)) { ++ /* Overloading the origidx variable to remember the coreid, ++ * this works because the core ids cannot be confused with ++ * core indices. ++ */ ++ *origidx = coreid; ++ if (coreid == CC_CORE_ID) ++ return CCREGS_FAST(sii); ++ else if (coreid == sih->buscoretype) ++ return PCIEREGS(sii); ++ } ++ INTR_OFF(sii, *intr_val); ++ *origidx = sii->curidx; ++ cc = ai_setcore(sih, coreid, 0); ++ return cc; ++} ++ ++/* restore coreidx and restore interrupt */ ++void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ if (SI_FAST(sii) ++ && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) ++ return; ++ ++ ai_setcoreidx(sih, coreid); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val) ++{ ++ struct si_info *sii = (struct si_info *)sih; ++ u32 *w = (u32 *) sii->curwrap; ++ W_REG(w + (offset / 4), val); ++ return; ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set ++ * operation, switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fiddling with interrupts or core ++ * switches is needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci ++ * registers and (on newer pci cores) chipcommon registers. ++ */ ++uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, ++ uint val) ++{ ++ uint origidx = 0; ++ u32 __iomem *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = false; ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ /* ++ * If pci/pcie, we can get at pci/pcie regs ++ * and on newer cores to chipc ++ */ ++ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ fast = true; ++ r = (u32 __iomem *)((__iomem char *)sii->curmap + ++ PCI_16KB0_CCREGS_OFFSET + regoff); ++ } else if (sii->pub.buscoreidx == coreidx) { ++ /* ++ * pci registers are at either in the last 2KB of ++ * an 8KB window or, in pcie and pci rev 13 at 8KB ++ */ ++ fast = true; ++ if (SI_FAST(sii)) ++ r = (u32 __iomem *)((__iomem char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (u32 __iomem *)((__iomem char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : ++ PCI_BAR0_PCIREGS_OFFSET) + regoff); ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = ai_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (u32 __iomem *) ((unsigned char __iomem *) ++ ai_setcoreidx(&sii->pub, coreidx) + regoff); ++ } ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_REG(r) & ~mask) | val; ++ W_REG(r, w); ++ } ++ ++ /* readback */ ++ w = R_REG(r); ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ ai_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return w; ++} ++ ++void ai_core_disable(struct si_pub *sih, u32 bits) ++{ ++ struct si_info *sii; ++ u32 dummy; ++ struct aidmp *ai; ++ ++ sii = (struct si_info *)sih; ++ ++ ai = sii->curwrap; ++ ++ /* if core is already in reset, just return */ ++ if (R_REG(&ai->resetctrl) & AIRC_RESET) ++ return; ++ ++ W_REG(&ai->ioctrl, bits); ++ dummy = R_REG(&ai->ioctrl); ++ udelay(10); ++ ++ W_REG(&ai->resetctrl, AIRC_RESET); ++ udelay(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits) ++{ ++ struct si_info *sii; ++ struct aidmp *ai; ++ u32 dummy; ++ ++ sii = (struct si_info *)sih; ++ ai = sii->curwrap; ++ ++ /* ++ * Must do the disable sequence first to work ++ * for arbitrary current core state. ++ */ ++ ai_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); ++ dummy = R_REG(&ai->ioctrl); ++ W_REG(&ai->resetctrl, 0); ++ udelay(1); ++ ++ W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN)); ++ dummy = R_REG(&ai->ioctrl); ++ udelay(1); ++} ++ ++/* return the slow clock source - LPO, XTAL, or PCI */ ++static uint ai_slowclk_src(struct si_info *sii) ++{ ++ struct chipcregs __iomem *cc; ++ u32 val; ++ ++ if (sii->pub.ccrev < 6) { ++ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, ++ &val); ++ if (val & PCI_CFG_GPIO_SCS) ++ return SCC_SS_PCI; ++ return SCC_SS_XTAL; ++ } else if (sii->pub.ccrev < 10) { ++ cc = (struct chipcregs __iomem *) ++ ai_setcoreidx(&sii->pub, sii->curidx); ++ return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK; ++ } else /* Insta-clock */ ++ return SCC_SS_XTAL; ++} ++ ++/* ++* return the ILP (slowclock) min or max frequency ++* precondition: we've established the chip has dynamic clk control ++*/ ++static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, ++ struct chipcregs __iomem *cc) ++{ ++ u32 slowclk; ++ uint div; ++ ++ slowclk = ai_slowclk_src(sii); ++ if (sii->pub.ccrev < 6) { ++ if (slowclk == SCC_SS_PCI) ++ return max_freq ? (PCIMAXFREQ / 64) ++ : (PCIMINFREQ / 64); ++ else ++ return max_freq ? (XTALMAXFREQ / 32) ++ : (XTALMINFREQ / 32); ++ } else if (sii->pub.ccrev < 10) { ++ div = 4 * ++ (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> ++ SCC_CD_SHIFT) + 1); ++ if (slowclk == SCC_SS_LPO) ++ return max_freq ? LPOMAXFREQ : LPOMINFREQ; ++ else if (slowclk == SCC_SS_XTAL) ++ return max_freq ? (XTALMAXFREQ / div) ++ : (XTALMINFREQ / div); ++ else if (slowclk == SCC_SS_PCI) ++ return max_freq ? (PCIMAXFREQ / div) ++ : (PCIMINFREQ / div); ++ } else { ++ /* Chipc rev 10 is InstaClock */ ++ div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT; ++ div = 4 * (div + 1); ++ return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); ++ } ++ return 0; ++} ++ ++static void ++ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc) ++{ ++ uint slowmaxfreq, pll_delay, slowclk; ++ uint pll_on_delay, fref_sel_delay; ++ ++ pll_delay = PLL_DELAY; ++ ++ /* ++ * If the slow clock is not sourced by the xtal then ++ * add the xtal_on_delay since the xtal will also be ++ * powered down by dynamic clk control logic. ++ */ ++ ++ slowclk = ai_slowclk_src(sii); ++ if (slowclk != SCC_SS_XTAL) ++ pll_delay += XTAL_ON_DELAY; ++ ++ /* Starting with 4318 it is ILP that is used for the delays */ ++ slowmaxfreq = ++ ai_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc); ++ ++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; ++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; ++ ++ W_REG(&cc->pll_on_delay, pll_on_delay); ++ W_REG(&cc->fref_sel_delay, fref_sel_delay); ++} ++ ++/* initialize power control delay registers */ ++void ai_clkctl_init(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ uint origidx = 0; ++ struct chipcregs __iomem *cc; ++ bool fast; ++ ++ if (!(sih->cccaps & CC_CAP_PWR_CTL)) ++ return; ++ ++ sii = (struct si_info *)sih; ++ fast = SI_FAST(sii); ++ if (!fast) { ++ origidx = sii->curidx; ++ cc = (struct chipcregs __iomem *) ++ ai_setcore(sih, CC_CORE_ID, 0); ++ if (cc == NULL) ++ return; ++ } else { ++ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); ++ if (cc == NULL) ++ return; ++ } ++ ++ /* set all Instaclk chip ILP to 1 MHz */ ++ if (sih->ccrev >= 10) ++ SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, ++ (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); ++ ++ ai_clkctl_setdelay(sii, cc); ++ ++ if (!fast) ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* ++ * return the value suitable for writing to the ++ * dot11 core FAST_PWRUP_DELAY register ++ */ ++u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ uint origidx = 0; ++ struct chipcregs __iomem *cc; ++ uint slowminfreq; ++ u16 fpdelay; ++ uint intr_val = 0; ++ bool fast; ++ ++ sii = (struct si_info *)sih; ++ if (sih->cccaps & CC_CAP_PMU) { ++ INTR_OFF(sii, intr_val); ++ fpdelay = si_pmu_fast_pwrup_delay(sih); ++ INTR_RESTORE(sii, intr_val); ++ return fpdelay; ++ } ++ ++ if (!(sih->cccaps & CC_CAP_PWR_CTL)) ++ return 0; ++ ++ fast = SI_FAST(sii); ++ fpdelay = 0; ++ if (!fast) { ++ origidx = sii->curidx; ++ INTR_OFF(sii, intr_val); ++ cc = (struct chipcregs __iomem *) ++ ai_setcore(sih, CC_CORE_ID, 0); ++ if (cc == NULL) ++ goto done; ++ } else { ++ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); ++ if (cc == NULL) ++ goto done; ++ } ++ ++ slowminfreq = ai_slowclk_freq(sii, false, cc); ++ fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + ++ (slowminfreq - 1)) / slowminfreq; ++ ++ done: ++ if (!fast) { ++ ai_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ } ++ return fpdelay; ++} ++ ++/* turn primary xtal and/or pll off/on */ ++int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) ++{ ++ struct si_info *sii; ++ u32 in, out, outen; ++ ++ sii = (struct si_info *)sih; ++ ++ /* pcie core doesn't have any mapping to control the xtal pu */ ++ if (PCIE(sii)) ++ return -1; ++ ++ pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in); ++ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out); ++ pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen); ++ ++ /* ++ * Avoid glitching the clock if GPRS is already using it. ++ * We can't actually read the state of the PLLPD so we infer it ++ * by the value of XTAL_PU which *is* readable via gpioin. ++ */ ++ if (on && (in & PCI_CFG_GPIO_XTAL)) ++ return 0; ++ ++ if (what & XTAL) ++ outen |= PCI_CFG_GPIO_XTAL; ++ if (what & PLL) ++ outen |= PCI_CFG_GPIO_PLL; ++ ++ if (on) { ++ /* turn primary xtal on */ ++ if (what & XTAL) { ++ out |= PCI_CFG_GPIO_XTAL; ++ if (what & PLL) ++ out |= PCI_CFG_GPIO_PLL; ++ pci_write_config_dword(sii->pbus, ++ PCI_GPIO_OUT, out); ++ pci_write_config_dword(sii->pbus, ++ PCI_GPIO_OUTEN, outen); ++ udelay(XTAL_ON_DELAY); ++ } ++ ++ /* turn pll on */ ++ if (what & PLL) { ++ out &= ~PCI_CFG_GPIO_PLL; ++ pci_write_config_dword(sii->pbus, ++ PCI_GPIO_OUT, out); ++ mdelay(2); ++ } ++ } else { ++ if (what & XTAL) ++ out &= ~PCI_CFG_GPIO_XTAL; ++ if (what & PLL) ++ out |= PCI_CFG_GPIO_PLL; ++ pci_write_config_dword(sii->pbus, ++ PCI_GPIO_OUT, out); ++ pci_write_config_dword(sii->pbus, ++ PCI_GPIO_OUTEN, outen); ++ } ++ ++ return 0; ++} ++ ++/* clk control mechanism through chipcommon, no policy checking */ ++static bool _ai_clkctl_cc(struct si_info *sii, uint mode) ++{ ++ uint origidx = 0; ++ struct chipcregs __iomem *cc; ++ u32 scc; ++ uint intr_val = 0; ++ bool fast = SI_FAST(sii); ++ ++ /* chipcommon cores prior to rev6 don't support dynamic clock control */ ++ if (sii->pub.ccrev < 6) ++ return false; ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ origidx = sii->curidx; ++ cc = (struct chipcregs __iomem *) ++ ai_setcore(&sii->pub, CC_CORE_ID, 0); ++ } else { ++ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); ++ if (cc == NULL) ++ goto done; ++ } ++ ++ if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20)) ++ goto done; ++ ++ switch (mode) { ++ case CLK_FAST: /* FORCEHT, fast (pll) clock */ ++ if (sii->pub.ccrev < 10) { ++ /* ++ * don't forget to force xtal back ++ * on before we clear SCC_DYN_XTAL.. ++ */ ++ ai_clkctl_xtal(&sii->pub, XTAL, ON); ++ SET_REG(&cc->slow_clk_ctl, ++ (SCC_XC | SCC_FS | SCC_IP), SCC_IP); ++ } else if (sii->pub.ccrev < 20) { ++ OR_REG(&cc->system_clk_ctl, SYCC_HR); ++ } else { ++ OR_REG(&cc->clk_ctl_st, CCS_FORCEHT); ++ } ++ ++ /* wait for the PLL */ ++ if (sii->pub.cccaps & CC_CAP_PMU) { ++ u32 htavail = CCS_HTAVAIL; ++ SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail) ++ == 0), PMU_MAX_TRANSITION_DLY); ++ } else { ++ udelay(PLL_DELAY); ++ } ++ break; ++ ++ case CLK_DYNAMIC: /* enable dynamic clock control */ ++ if (sii->pub.ccrev < 10) { ++ scc = R_REG(&cc->slow_clk_ctl); ++ scc &= ~(SCC_FS | SCC_IP | SCC_XC); ++ if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) ++ scc |= SCC_XC; ++ W_REG(&cc->slow_clk_ctl, scc); ++ ++ /* ++ * for dynamic control, we have to ++ * release our xtal_pu "force on" ++ */ ++ if (scc & SCC_XC) ++ ai_clkctl_xtal(&sii->pub, XTAL, OFF); ++ } else if (sii->pub.ccrev < 20) { ++ /* Instaclock */ ++ AND_REG(&cc->system_clk_ctl, ~SYCC_HR); ++ } else { ++ AND_REG(&cc->clk_ctl_st, ~CCS_FORCEHT); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ done: ++ if (!fast) { ++ ai_setcoreidx(&sii->pub, origidx); ++ INTR_RESTORE(sii, intr_val); ++ } ++ return mode == CLK_FAST; ++} ++ ++/* ++ * clock control policy function throught chipcommon ++ * ++ * set dynamic clk control mode (forceslow, forcefast, dynamic) ++ * returns true if we are forcing fast clock ++ * this is a wrapper over the next internal function ++ * to allow flexible policy settings for outside caller ++ */ ++bool ai_clkctl_cc(struct si_pub *sih, uint mode) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ /* chipcommon cores prior to rev6 don't support dynamic clock control */ ++ if (sih->ccrev < 6) ++ return false; ++ ++ if (PCI_FORCEHT(sii)) ++ return mode == CLK_FAST; ++ ++ return _ai_clkctl_cc(sii, mode); ++} ++ ++/* Build device path */ ++int ai_devpath(struct si_pub *sih, char *path, int size) ++{ ++ int slen; ++ ++ if (!path || size <= 0) ++ return -1; ++ ++ slen = snprintf(path, (size_t) size, "pci/%u/%u/", ++ ((struct si_info *)sih)->pbus->bus->number, ++ PCI_SLOT(((struct pci_dev *) ++ (((struct si_info *)(sih))->pbus))->devfn)); ++ ++ if (slen < 0 || slen >= size) { ++ path[0] = '\0'; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void ai_pci_up(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ if (PCI_FORCEHT(sii)) ++ _ai_clkctl_cc(sii, CLK_FAST); ++ ++ if (PCIE(sii)) ++ pcicore_up(sii->pch, SI_PCIUP); ++ ++} ++ ++/* Unconfigure and/or apply various WARs when system is going to sleep mode */ ++void ai_pci_sleep(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ pcicore_sleep(sii->pch); ++} ++ ++/* Unconfigure and/or apply various WARs when going down */ ++void ai_pci_down(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ /* release FORCEHT since chip is going to "down" state */ ++ if (PCI_FORCEHT(sii)) ++ _ai_clkctl_cc(sii, CLK_DYNAMIC); ++ ++ pcicore_down(sii->pch, SI_PCIDOWN); ++} ++ ++/* ++ * Configure the pci core for pci client (NIC) action ++ * coremask is the bitvec of cores by index to be enabled. ++ */ ++void ai_pci_setup(struct si_pub *sih, uint coremask) ++{ ++ struct si_info *sii; ++ struct sbpciregs __iomem *regs = NULL; ++ u32 siflag = 0, w; ++ uint idx = 0; ++ ++ sii = (struct si_info *)sih; ++ ++ if (PCI(sii)) { ++ /* get current core index */ ++ idx = sii->curidx; ++ ++ /* we interrupt on this backplane flag number */ ++ siflag = ai_flag(sih); ++ ++ /* switch over to pci core */ ++ regs = ai_setcoreidx(sih, sii->pub.buscoreidx); ++ } ++ ++ /* ++ * Enable sb->pci interrupts. Assume ++ * PCI rev 2.3 support was added in pci core rev 6 and things changed.. ++ */ ++ if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { ++ /* pci config write to set this core bit in PCIIntMask */ ++ pci_read_config_dword(sii->pbus, PCI_INT_MASK, &w); ++ w |= (coremask << PCI_SBIM_SHIFT); ++ pci_write_config_dword(sii->pbus, PCI_INT_MASK, w); ++ } else { ++ /* set sbintvec bit for our flag number */ ++ ai_setint(sih, siflag); ++ } ++ ++ if (PCI(sii)) { ++ pcicore_pci_setup(sii->pch, regs); ++ ++ /* switch back to previous core */ ++ ai_setcoreidx(sih, idx); ++ } ++} ++ ++/* ++ * Fixup SROMless PCI device's configuration. ++ * The current core may be changed upon return. ++ */ ++int ai_pci_fixcfg(struct si_pub *sih) ++{ ++ uint origidx; ++ void __iomem *regs = NULL; ++ struct si_info *sii = (struct si_info *)sih; ++ ++ /* Fixup PI in SROM shadow area to enable the correct PCI core access */ ++ /* save the current index */ ++ origidx = ai_coreidx(&sii->pub); ++ ++ /* check 'pi' is correct and fix it if not */ ++ regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0); ++ if (sii->pub.buscoretype == PCIE_CORE_ID) ++ pcicore_fixcfg_pcie(sii->pch, ++ (struct sbpcieregs __iomem *)regs); ++ else if (sii->pub.buscoretype == PCI_CORE_ID) ++ pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs); ++ ++ /* restore the original index */ ++ ai_setcoreidx(&sii->pub, origidx); ++ ++ pcicore_hwup(sii->pch); ++ return 0; ++} ++ ++/* mask&set gpiocontrol bits */ ++u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority) ++{ ++ uint regoff; ++ ++ regoff = offsetof(struct chipcregs, gpiocontrol); ++ return ai_corereg(sih, SI_CC_IDX, regoff, mask, val); ++} ++ ++void ai_chipcontrl_epa4331(struct si_pub *sih, bool on) ++{ ++ struct si_info *sii; ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ u32 val; ++ ++ sii = (struct si_info *)sih; ++ origidx = ai_coreidx(sih); ++ ++ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(&cc->chipcontrol); ++ ++ if (on) { ++ if (sih->chippkg == 9 || sih->chippkg == 0xb) ++ /* Ext PA Controls for 4331 12x9 Package */ ++ W_REG(&cc->chipcontrol, val | ++ CCTRL4331_EXTPA_EN | ++ CCTRL4331_EXTPA_ON_GPIO2_5); ++ else ++ /* Ext PA Controls for 4331 12x12 Package */ ++ W_REG(&cc->chipcontrol, ++ val | CCTRL4331_EXTPA_EN); ++ } else { ++ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(&cc->chipcontrol, val); ++ } ++ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* Enable BT-COEX & Ex-PA for 4313 */ ++void ai_epa_4313war(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ ++ sii = (struct si_info *)sih; ++ origidx = ai_coreidx(sih); ++ ++ cc = ai_setcore(sih, CC_CORE_ID, 0); ++ ++ /* EPA Fix */ ++ W_REG(&cc->gpiocontrol, ++ R_REG(&cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); ++ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* check if the device is removed */ ++bool ai_deviceremoved(struct si_pub *sih) ++{ ++ u32 w; ++ struct si_info *sii; ++ ++ sii = (struct si_info *)sih; ++ ++ pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w); ++ if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM) ++ return true; ++ ++ return false; ++} ++ ++bool ai_is_sprom_available(struct si_pub *sih) ++{ ++ if (sih->ccrev >= 31) { ++ struct si_info *sii; ++ uint origidx; ++ struct chipcregs __iomem *cc; ++ u32 sromctrl; ++ ++ if ((sih->cccaps & CC_CAP_SROM) == 0) ++ return false; ++ ++ sii = (struct si_info *)sih; ++ origidx = sii->curidx; ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ sromctrl = R_REG(&cc->sromcontrol); ++ ai_setcoreidx(sih, origidx); ++ return sromctrl & SRC_PRESENT; ++ } ++ ++ switch (sih->chip) { ++ case BCM4313_CHIP_ID: ++ return (sih->chipst & CST4313_SPROM_PRESENT) != 0; ++ default: ++ return true; ++ } ++} ++ ++bool ai_is_otp_disabled(struct si_pub *sih) ++{ ++ switch (sih->chip) { ++ case BCM4313_CHIP_ID: ++ return (sih->chipst & CST4313_OTP_PRESENT) == 0; ++ /* These chips always have their OTP on */ ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ default: ++ return false; ++ } ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h.orig 2011-11-09 13:46:58.239800709 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h 2011-11-09 13:47:16.991566278 -0500 +@@ -0,0 +1,378 @@ ++/* ++ * Copyright (c) 2011 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_AIUTILS_H_ ++#define _BRCM_AIUTILS_H_ ++ ++#include "types.h" ++ ++/* ++ * SOC Interconnect Address Map. ++ * All regions may not exist on all chips. ++ */ ++/* each core gets 4Kbytes for registers */ ++#define SI_CORE_SIZE 0x1000 ++/* ++ * Max cores (this is arbitrary, for software ++ * convenience and could be changed if we ++ * make any larger chips ++ */ ++#define SI_MAXCORES 16 ++ ++/* Client Mode sb2pcitranslation2 size in bytes */ ++#define SI_PCI_DMA_SZ 0x40000000 ++ ++/* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ ++#define SI_PCIE_DMA_H32 0x80000000 ++ ++/* core codes */ ++#define NODEV_CORE_ID 0x700 /* Invalid coreid */ ++#define CC_CORE_ID 0x800 /* chipcommon core */ ++#define ILINE20_CORE_ID 0x801 /* iline20 core */ ++#define SRAM_CORE_ID 0x802 /* sram core */ ++#define SDRAM_CORE_ID 0x803 /* sdram core */ ++#define PCI_CORE_ID 0x804 /* pci core */ ++#define MIPS_CORE_ID 0x805 /* mips core */ ++#define ENET_CORE_ID 0x806 /* enet mac core */ ++#define CODEC_CORE_ID 0x807 /* v90 codec core */ ++#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ ++#define ADSL_CORE_ID 0x809 /* ADSL core */ ++#define ILINE100_CORE_ID 0x80a /* iline100 core */ ++#define IPSEC_CORE_ID 0x80b /* ipsec core */ ++#define UTOPIA_CORE_ID 0x80c /* utopia core */ ++#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ ++#define SOCRAM_CORE_ID 0x80e /* internal memory core */ ++#define MEMC_CORE_ID 0x80f /* memc sdram core */ ++#define OFDM_CORE_ID 0x810 /* OFDM phy core */ ++#define EXTIF_CORE_ID 0x811 /* external interface core */ ++#define D11_CORE_ID 0x812 /* 802.11 MAC core */ ++#define APHY_CORE_ID 0x813 /* 802.11a phy core */ ++#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ ++#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ ++#define MIPS33_CORE_ID 0x816 /* mips3302 core */ ++#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ ++#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ ++#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ ++#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ ++#define SDIOH_CORE_ID 0x81b /* sdio host core */ ++#define ROBO_CORE_ID 0x81c /* roboswitch core */ ++#define ATA100_CORE_ID 0x81d /* parallel ATA core */ ++#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ ++#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ ++#define PCIE_CORE_ID 0x820 /* pci express core */ ++#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ ++#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ ++#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ ++#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ ++#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ ++#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ ++#define PMU_CORE_ID 0x827 /* PMU core */ ++#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ ++#define SDIOD_CORE_ID 0x829 /* SDIO device core */ ++#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ ++#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ ++#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ ++#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ ++#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ ++#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ ++#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ ++#define SC_CORE_ID 0x831 /* shared common core */ ++#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ ++#define SPIH_CORE_ID 0x833 /* SPI host core */ ++#define I2S_CORE_ID 0x834 /* I2S core */ ++#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ ++#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ ++#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ ++#define DEF_AI_COMP 0xfff /* Default component, in ai chips it ++ * maps all unused address ranges ++ */ ++ ++/* chipcommon being the first core: */ ++#define SI_CC_IDX 0 ++ ++/* SOC Interconnect types (aka chip types) */ ++#define SOCI_AI 1 ++ ++/* Common core control flags */ ++#define SICF_BIST_EN 0x8000 ++#define SICF_PME_EN 0x4000 ++#define SICF_CORE_BITS 0x3ffc ++#define SICF_FGC 0x0002 ++#define SICF_CLOCK_EN 0x0001 ++ ++/* Common core status flags */ ++#define SISF_BIST_DONE 0x8000 ++#define SISF_BIST_ERROR 0x4000 ++#define SISF_GATED_CLK 0x2000 ++#define SISF_DMA64 0x1000 ++#define SISF_CORE_BITS 0x0fff ++ ++/* A register that is common to all cores to ++ * communicate w/PMU regarding clock control. ++ */ ++#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ ++ ++/* clk_ctl_st register */ ++#define CCS_FORCEALP 0x00000001 /* force ALP request */ ++#define CCS_FORCEHT 0x00000002 /* force HT request */ ++#define CCS_FORCEILP 0x00000004 /* force ILP request */ ++#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ ++#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ ++#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ ++#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ ++#define CCS_ERSRC_REQ_SHIFT 8 ++#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ ++#define CCS_HTAVAIL 0x00020000 /* HT is available */ ++#define CCS_BP_ON_APL 0x00040000 /* RO: running on ALP clock */ ++#define CCS_BP_ON_HT 0x00080000 /* RO: running on HT clock */ ++#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ ++#define CCS_ERSRC_STS_SHIFT 24 ++ ++/* HT avail in chipc and pcmcia on 4328a0 */ ++#define CCS0_HTAVAIL 0x00010000 ++/* ALP avail in chipc and pcmcia on 4328a0 */ ++#define CCS0_ALPAVAIL 0x00020000 ++ ++/* Not really related to SOC Interconnect, but a couple of software ++ * conventions for the use the flash space: ++ */ ++ ++/* Minumum amount of flash we support */ ++#define FLASH_MIN 0x00020000 /* Minimum flash size */ ++ ++#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ ++ ++/* gpiotimerval */ ++#define GPIO_ONTIME_SHIFT 16 ++ ++/* Fields in clkdiv */ ++#define CLKD_OTP 0x000f0000 ++#define CLKD_OTP_SHIFT 16 ++ ++/* Package IDs */ ++#define BCM4717_PKG_ID 9 /* 4717 package id */ ++#define BCM4718_PKG_ID 10 /* 4718 package id */ ++#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ ++ ++/* these are router chips */ ++#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ ++#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ ++#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ ++ ++/* dynamic clock control defines */ ++#define LPOMINFREQ 25000 /* low power oscillator min */ ++#define LPOMAXFREQ 43000 /* low power oscillator max */ ++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */ ++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ ++#define PCIMINFREQ 25000000 /* 25 MHz */ ++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ ++ ++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ ++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ ++ ++/* clkctl xtal what flags */ ++#define XTAL 0x1 /* primary crystal oscillator (2050) */ ++#define PLL 0x2 /* main chip pll */ ++ ++/* clkctl clk mode */ ++#define CLK_FAST 0 /* force fast (pll) clock */ ++#define CLK_DYNAMIC 2 /* enable dynamic clock control */ ++ ++/* GPIO usage priorities */ ++#define GPIO_DRV_PRIORITY 0 /* Driver */ ++#define GPIO_APP_PRIORITY 1 /* Application */ ++#define GPIO_HI_PRIORITY 2 /* Highest priority. Ignore GPIO ++ * reservation ++ */ ++ ++/* GPIO pull up/down */ ++#define GPIO_PULLUP 0 ++#define GPIO_PULLDN 1 ++ ++/* GPIO event regtype */ ++#define GPIO_REGEVT 0 /* GPIO register event */ ++#define GPIO_REGEVT_INTMSK 1 /* GPIO register event int mask */ ++#define GPIO_REGEVT_INTPOL 2 /* GPIO register event int polarity */ ++ ++/* device path */ ++#define SI_DEVPATH_BUFSZ 16 /* min buffer size in bytes */ ++ ++/* SI routine enumeration: to be used by update function with multiple hooks */ ++#define SI_DOATTACH 1 ++#define SI_PCIDOWN 2 ++#define SI_PCIUP 3 ++ ++/* ++ * Data structure to export all chip specific common variables ++ * public (read-only) portion of aiutils handle returned by si_attach() ++ */ ++struct si_pub { ++ uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */ ++ uint buscorerev; /* buscore rev */ ++ uint buscoreidx; /* buscore index */ ++ int ccrev; /* chip common core rev */ ++ u32 cccaps; /* chip common capabilities */ ++ u32 cccaps_ext; /* chip common capabilities extension */ ++ int pmurev; /* pmu core rev */ ++ u32 pmucaps; /* pmu capabilities */ ++ uint boardtype; /* board type */ ++ uint boardvendor; /* board vendor */ ++ uint boardflags; /* board flags */ ++ uint boardflags2; /* board flags2 */ ++ uint chip; /* chip number */ ++ uint chiprev; /* chip revision */ ++ uint chippkg; /* chip package option */ ++ u32 chipst; /* chip status */ ++ bool issim; /* chip is in simulation or emulation */ ++ uint socirev; /* SOC interconnect rev */ ++ bool pci_pr32414; ++ ++}; ++ ++struct pci_dev; ++ ++struct gpioh_item { ++ void *arg; ++ bool level; ++ void (*handler) (u32 stat, void *arg); ++ u32 event; ++ struct gpioh_item *next; ++}; ++ ++/* misc si info needed by some of the routines */ ++struct si_info { ++ struct si_pub pub; /* back plane public state (must be first) */ ++ struct pci_dev *pbus; /* handle to pci bus */ ++ uint dev_coreid; /* the core provides driver functions */ ++ void *intr_arg; /* interrupt callback function arg */ ++ u32 (*intrsoff_fn) (void *intr_arg); /* turns chip interrupts off */ ++ /* restore chip interrupts */ ++ void (*intrsrestore_fn) (void *intr_arg, u32 arg); ++ /* check if interrupts are enabled */ ++ bool (*intrsenabled_fn) (void *intr_arg); ++ ++ struct pcicore_info *pch; /* PCI/E core handle */ ++ ++ struct list_head var_list; /* list of srom variables */ ++ ++ void __iomem *curmap; /* current regs va */ ++ void __iomem *regs[SI_MAXCORES]; /* other regs va */ ++ ++ uint curidx; /* current core index */ ++ uint numcores; /* # discovered cores */ ++ uint coreid[SI_MAXCORES]; /* id of each core */ ++ u32 coresba[SI_MAXCORES]; /* backplane address of each core */ ++ void *regs2[SI_MAXCORES]; /* 2nd virtual address per core (usbh20) */ ++ u32 coresba2[SI_MAXCORES]; /* 2nd phys address per core (usbh20) */ ++ u32 coresba_size[SI_MAXCORES]; /* backplane address space size */ ++ u32 coresba2_size[SI_MAXCORES]; /* second address space size */ ++ ++ void *curwrap; /* current wrapper va */ ++ void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ ++ u32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ ++ ++ u32 cia[SI_MAXCORES]; /* erom cia entry for each core */ ++ u32 cib[SI_MAXCORES]; /* erom cia entry for each core */ ++ u32 oob_router; /* oob router registers for axi */ ++}; ++ ++/* ++ * Many of the routines below take an 'sih' handle as their first arg. ++ * Allocate this by calling si_attach(). Free it by calling si_detach(). ++ * At any one time, the sih is logically focused on one particular si core ++ * (the "current core"). ++ * Use si_setcore() or si_setcoreidx() to change the association to another core ++ */ ++ ++ ++/* AMBA Interconnect exported externs */ ++extern uint ai_flag(struct si_pub *sih); ++extern void ai_setint(struct si_pub *sih, int siflag); ++extern uint ai_coreidx(struct si_pub *sih); ++extern uint ai_corevendor(struct si_pub *sih); ++extern uint ai_corerev(struct si_pub *sih); ++extern bool ai_iscoreup(struct si_pub *sih); ++extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); ++extern void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val); ++extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); ++extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, ++ uint val); ++extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); ++extern void ai_core_disable(struct si_pub *sih, u32 bits); ++extern int ai_numaddrspaces(struct si_pub *sih); ++extern u32 ai_addrspace(struct si_pub *sih, uint asidx); ++extern u32 ai_addrspacesize(struct si_pub *sih, uint asidx); ++extern void ai_write_wrap_reg(struct si_pub *sih, u32 offset, u32 val); ++ ++/* === exported functions === */ ++extern struct si_pub *ai_attach(void __iomem *regs, struct pci_dev *sdh); ++extern void ai_detach(struct si_pub *sih); ++extern uint ai_coreid(struct si_pub *sih); ++extern uint ai_corerev(struct si_pub *sih); ++extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, ++ uint val); ++extern void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val); ++extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); ++extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); ++extern bool ai_iscoreup(struct si_pub *sih); ++extern uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit); ++extern void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx); ++extern void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit); ++extern void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, ++ uint *origidx, uint *intr_val); ++extern void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val); ++extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); ++extern void ai_core_disable(struct si_pub *sih, u32 bits); ++extern u32 ai_alp_clock(struct si_pub *sih); ++extern u32 ai_ilp_clock(struct si_pub *sih); ++extern void ai_pci_setup(struct si_pub *sih, uint coremask); ++extern void ai_setint(struct si_pub *sih, int siflag); ++extern bool ai_backplane64(struct si_pub *sih); ++extern void ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, ++ void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg); ++extern void ai_deregister_intr_callback(struct si_pub *sih); ++extern void ai_clkctl_init(struct si_pub *sih); ++extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); ++extern bool ai_clkctl_cc(struct si_pub *sih, uint mode); ++extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on); ++extern bool ai_deviceremoved(struct si_pub *sih); ++extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, ++ u8 priority); ++ ++/* OTP status */ ++extern bool ai_is_otp_disabled(struct si_pub *sih); ++ ++/* SPROM availability */ ++extern bool ai_is_sprom_available(struct si_pub *sih); ++ ++/* ++ * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. ++ * The returned path is NULL terminated and has trailing '/'. ++ * Return 0 on success, nonzero otherwise. ++ */ ++extern int ai_devpath(struct si_pub *sih, char *path, int size); ++ ++extern void ai_pci_sleep(struct si_pub *sih); ++extern void ai_pci_down(struct si_pub *sih); ++extern void ai_pci_up(struct si_pub *sih); ++extern int ai_pci_fixcfg(struct si_pub *sih); ++ ++extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on); ++/* Enable Ex-PA for 4313 */ ++extern void ai_epa_4313war(struct si_pub *sih); ++ ++#endif /* _BRCM_AIUTILS_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c.orig 2011-11-09 13:46:58.240800696 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c 2011-11-09 13:47:16.992566265 -0500 +@@ -0,0 +1,1241 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include ++ ++#include "rate.h" ++#include "scb.h" ++#include "phy/phy_hal.h" ++#include "antsel.h" ++#include "main.h" ++#include "ampdu.h" ++ ++/* max number of mpdus in an ampdu */ ++#define AMPDU_MAX_MPDU 32 ++/* max number of mpdus in an ampdu to a legacy */ ++#define AMPDU_NUM_MPDU_LEGACY 16 ++/* max Tx ba window size (in pdu) */ ++#define AMPDU_TX_BA_MAX_WSIZE 64 ++/* default Tx ba window size (in pdu) */ ++#define AMPDU_TX_BA_DEF_WSIZE 64 ++/* default Rx ba window size (in pdu) */ ++#define AMPDU_RX_BA_DEF_WSIZE 64 ++/* max Rx ba window size (in pdu) */ ++#define AMPDU_RX_BA_MAX_WSIZE 64 ++/* max dur of tx ampdu (in msec) */ ++#define AMPDU_MAX_DUR 5 ++/* default tx retry limit */ ++#define AMPDU_DEF_RETRY_LIMIT 5 ++/* default tx retry limit at reg rate */ ++#define AMPDU_DEF_RR_RETRY_LIMIT 2 ++/* default weight of ampdu in txfifo */ ++#define AMPDU_DEF_TXPKT_WEIGHT 2 ++/* default ffpld reserved bytes */ ++#define AMPDU_DEF_FFPLD_RSVD 2048 ++/* # of inis to be freed on detach */ ++#define AMPDU_INI_FREE 10 ++/* max # of mpdus released at a time */ ++#define AMPDU_SCB_MAX_RELEASE 20 ++ ++#define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */ ++#define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu ++ * without underflows ++ */ ++#define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */ ++#define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */ ++#define FFPLD_PLD_INCR 1000 /* increments in bytes */ ++#define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we ++ * accumulate between resets. ++ */ ++ ++#define AMPDU_DELIMITER_LEN 4 ++ ++/* max allowed number of mpdus in an ampdu (2 streams) */ ++#define AMPDU_NUM_MPDU 16 ++ ++#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE) ++ ++/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */ ++#define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\ ++ AMPDU_DELIMITER_LEN + 3\ ++ + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN) ++ ++/* modulo add/sub, bound = 2^k */ ++#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) ++#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) ++ ++/* structure to hold tx fifo information and pre-loading state ++ * counters specific to tx underflows of ampdus ++ * some counters might be redundant with the ones in wlc or ampdu structures. ++ * This allows to maintain a specific state independently of ++ * how often and/or when the wlc counters are updated. ++ * ++ * ampdu_pld_size: number of bytes to be pre-loaded ++ * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu ++ * prev_txfunfl: num of underflows last read from the HW macstats counter ++ * accum_txfunfl: num of underflows since we modified pld params ++ * accum_txampdu: num of tx ampdu since we modified pld params ++ * prev_txampdu: previous reading of tx ampdu ++ * dmaxferrate: estimated dma avg xfer rate in kbits/sec ++ */ ++struct brcms_fifo_info { ++ u16 ampdu_pld_size; ++ u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; ++ u16 prev_txfunfl; ++ u32 accum_txfunfl; ++ u32 accum_txampdu; ++ u32 prev_txampdu; ++ u32 dmaxferrate; ++}; ++ ++/* AMPDU module specific state ++ * ++ * wlc: pointer to main wlc structure ++ * scb_handle: scb cubby handle to retrieve data from scb ++ * ini_enable: per-tid initiator enable/disable of ampdu ++ * ba_tx_wsize: Tx ba window size (in pdu) ++ * ba_rx_wsize: Rx ba window size (in pdu) ++ * retry_limit: mpdu transmit retry limit ++ * rr_retry_limit: mpdu transmit retry limit at regular rate ++ * retry_limit_tid: per-tid mpdu transmit retry limit ++ * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate ++ * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec ++ * max_pdu: max pdus allowed in ampdu ++ * dur: max duration of an ampdu (in msec) ++ * txpkt_weight: weight of ampdu in txfifo; reduces rate lag ++ * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes ++ * ffpld_rsvd: number of bytes to reserve for preload ++ * max_txlen: max size of ampdu per mcs, bw and sgi ++ * mfbr: enable multiple fallback rate ++ * tx_max_funl: underflows should be kept such that ++ * (tx_max_funfl*underflows) < tx frames ++ * fifo_tb: table of fifo infos ++ */ ++struct ampdu_info { ++ struct brcms_c_info *wlc; ++ int scb_handle; ++ u8 ini_enable[AMPDU_MAX_SCB_TID]; ++ u8 ba_tx_wsize; ++ u8 ba_rx_wsize; ++ u8 retry_limit; ++ u8 rr_retry_limit; ++ u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; ++ u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID]; ++ u8 mpdu_density; ++ s8 max_pdu; ++ u8 dur; ++ u8 txpkt_weight; ++ u8 rx_factor; ++ u32 ffpld_rsvd; ++ u32 max_txlen[MCS_TABLE_SIZE][2][2]; ++ bool mfbr; ++ u32 tx_max_funl; ++ struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO]; ++}; ++ ++/* used for flushing ampdu packets */ ++struct cb_del_ampdu_pars { ++ struct ieee80211_sta *sta; ++ u16 tid; ++}; ++ ++static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur) ++{ ++ u32 rate, mcs; ++ ++ for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) { ++ /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */ ++ /* 20MHz, No SGI */ ++ rate = mcs_2_rate(mcs, false, false); ++ ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3; ++ /* 40 MHz, No SGI */ ++ rate = mcs_2_rate(mcs, true, false); ++ ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3; ++ /* 20MHz, SGI */ ++ rate = mcs_2_rate(mcs, false, true); ++ ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3; ++ /* 40 MHz, SGI */ ++ rate = mcs_2_rate(mcs, true, true); ++ ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3; ++ } ++} ++ ++static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu) ++{ ++ if (BRCMS_PHY_11N_CAP(ampdu->wlc->band)) ++ return true; ++ else ++ return false; ++} ++ ++static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on) ++{ ++ struct brcms_c_info *wlc = ampdu->wlc; ++ ++ wlc->pub->_ampdu = false; ++ ++ if (on) { ++ if (!(wlc->pub->_n_enab & SUPPORT_11N)) { ++ wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not " ++ "nmode enabled\n", wlc->pub->unit); ++ return -ENOTSUPP; ++ } ++ if (!brcms_c_ampdu_cap(ampdu)) { ++ wiphy_err(ampdu->wlc->wiphy, "wl%d: device not " ++ "ampdu capable\n", wlc->pub->unit); ++ return -ENOTSUPP; ++ } ++ wlc->pub->_ampdu = on; ++ } ++ ++ return 0; ++} ++ ++static void brcms_c_ffpld_init(struct ampdu_info *ampdu) ++{ ++ int i, j; ++ struct brcms_fifo_info *fifo; ++ ++ for (j = 0; j < NUM_FFPLD_FIFO; j++) { ++ fifo = (ampdu->fifo_tb + j); ++ fifo->ampdu_pld_size = 0; ++ for (i = 0; i <= FFPLD_MAX_MCS; i++) ++ fifo->mcs2ampdu_table[i] = 255; ++ fifo->dmaxferrate = 0; ++ fifo->accum_txampdu = 0; ++ fifo->prev_txfunfl = 0; ++ fifo->accum_txfunfl = 0; ++ ++ } ++} ++ ++struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc) ++{ ++ struct ampdu_info *ampdu; ++ int i; ++ ++ ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC); ++ if (!ampdu) ++ return NULL; ++ ++ ampdu->wlc = wlc; ++ ++ for (i = 0; i < AMPDU_MAX_SCB_TID; i++) ++ ampdu->ini_enable[i] = true; ++ /* Disable ampdu for VO by default */ ++ ampdu->ini_enable[PRIO_8021D_VO] = false; ++ ampdu->ini_enable[PRIO_8021D_NC] = false; ++ ++ /* Disable ampdu for BK by default since not enough fifo space */ ++ ampdu->ini_enable[PRIO_8021D_NONE] = false; ++ ampdu->ini_enable[PRIO_8021D_BK] = false; ++ ++ ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE; ++ ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE; ++ ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY; ++ ampdu->max_pdu = AUTO; ++ ampdu->dur = AMPDU_MAX_DUR; ++ ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT; ++ ++ ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD; ++ /* ++ * bump max ampdu rcv size to 64k for all 11n ++ * devices except 4321A0 and 4321A1 ++ */ ++ if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2)) ++ ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K; ++ else ++ ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT; ++ ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT; ++ ++ for (i = 0; i < AMPDU_MAX_SCB_TID; i++) { ++ ampdu->retry_limit_tid[i] = ampdu->retry_limit; ++ ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit; ++ } ++ ++ brcms_c_scb_ampdu_update_max_txlen(ampdu, ampdu->dur); ++ ampdu->mfbr = false; ++ /* try to set ampdu to the default value */ ++ brcms_c_ampdu_set(ampdu, wlc->pub->_ampdu); ++ ++ ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL; ++ brcms_c_ffpld_init(ampdu); ++ ++ return ampdu; ++} ++ ++void brcms_c_ampdu_detach(struct ampdu_info *ampdu) ++{ ++ kfree(ampdu); ++} ++ ++static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu, ++ struct scb *scb) ++{ ++ struct scb_ampdu *scb_ampdu = &scb->scb_ampdu; ++ int i; ++ ++ scb_ampdu->max_pdu = AMPDU_NUM_MPDU; ++ ++ /* go back to legacy size if some preloading is occurring */ ++ for (i = 0; i < NUM_FFPLD_FIFO; i++) { ++ if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR) ++ scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY; ++ } ++ ++ /* apply user override */ ++ if (ampdu->max_pdu != AUTO) ++ scb_ampdu->max_pdu = (u8) ampdu->max_pdu; ++ ++ scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, ++ AMPDU_SCB_MAX_RELEASE); ++ ++ if (scb_ampdu->max_rx_ampdu_bytes) ++ scb_ampdu->release = min_t(u8, scb_ampdu->release, ++ scb_ampdu->max_rx_ampdu_bytes / 1600); ++ ++ scb_ampdu->release = min(scb_ampdu->release, ++ ampdu->fifo_tb[TX_AC_BE_FIFO]. ++ mcs2ampdu_table[FFPLD_MAX_MCS]); ++} ++ ++static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu) ++{ ++ brcms_c_scb_ampdu_update_config(ampdu, &du->wlc->pri_scb); ++} ++ ++static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f) ++{ ++ int i; ++ u32 phy_rate, dma_rate, tmp; ++ u8 max_mpdu; ++ struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f); ++ ++ /* recompute the dma rate */ ++ /* note : we divide/multiply by 100 to avoid integer overflows */ ++ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], ++ AMPDU_NUM_MPDU_LEGACY); ++ phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false); ++ dma_rate = ++ (((phy_rate / 100) * ++ (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) ++ / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; ++ fifo->dmaxferrate = dma_rate; ++ ++ /* fill up the mcs2ampdu table; do not recalc the last mcs */ ++ dma_rate = dma_rate >> 7; ++ for (i = 0; i < FFPLD_MAX_MCS; i++) { ++ /* shifting to keep it within integer range */ ++ phy_rate = mcs_2_rate(i, true, false) >> 7; ++ if (phy_rate > dma_rate) { ++ tmp = ((fifo->ampdu_pld_size * phy_rate) / ++ ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1; ++ tmp = min_t(u32, tmp, 255); ++ fifo->mcs2ampdu_table[i] = (u8) tmp; ++ } ++ } ++} ++ ++/* evaluate the dma transfer rate using the tx underflows as feedback. ++ * If necessary, increase tx fifo preloading. If not enough, ++ * decrease maximum ampdu size for each mcs till underflows stop ++ * Return 1 if pre-loading not active, -1 if not an underflow event, ++ * 0 if pre-loading module took care of the event. ++ */ ++static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid) ++{ ++ struct ampdu_info *ampdu = wlc->ampdu; ++ u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false); ++ u32 txunfl_ratio; ++ u8 max_mpdu; ++ u32 current_ampdu_cnt = 0; ++ u16 max_pld_size; ++ u32 new_txunfl; ++ struct brcms_fifo_info *fifo = (ampdu->fifo_tb + fid); ++ uint xmtfifo_sz; ++ u16 cur_txunfl; ++ ++ /* return if we got here for a different reason than underflows */ ++ cur_txunfl = brcms_b_read_shm(wlc->hw, ++ M_UCODE_MACSTAT + ++ offsetof(struct macstat, txfunfl[fid])); ++ new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl); ++ if (new_txunfl == 0) { ++ BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n"); ++ return -1; ++ } ++ fifo->prev_txfunfl = cur_txunfl; ++ ++ if (!ampdu->tx_max_funl) ++ return 1; ++ ++ /* check if fifo is big enough */ ++ if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz)) ++ return -1; ++ ++ if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd) ++ return 1; ++ ++ max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd; ++ fifo->accum_txfunfl += new_txunfl; ++ ++ /* we need to wait for at least 10 underflows */ ++ if (fifo->accum_txfunfl < 10) ++ return 0; ++ ++ BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n", ++ current_ampdu_cnt, fifo->accum_txfunfl); ++ ++ /* ++ compute the current ratio of tx unfl per ampdu. ++ When the current ampdu count becomes too ++ big while the ratio remains small, we reset ++ the current count in order to not ++ introduce too big of a latency in detecting a ++ large amount of tx underflows later. ++ */ ++ ++ txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl; ++ ++ if (txunfl_ratio > ampdu->tx_max_funl) { ++ if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) ++ fifo->accum_txfunfl = 0; ++ ++ return 0; ++ } ++ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], ++ AMPDU_NUM_MPDU_LEGACY); ++ ++ /* In case max value max_pdu is already lower than ++ the fifo depth, there is nothing more we can do. ++ */ ++ ++ if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) { ++ fifo->accum_txfunfl = 0; ++ return 0; ++ } ++ ++ if (fifo->ampdu_pld_size < max_pld_size) { ++ ++ /* increment by TX_FIFO_PLD_INC bytes */ ++ fifo->ampdu_pld_size += FFPLD_PLD_INCR; ++ if (fifo->ampdu_pld_size > max_pld_size) ++ fifo->ampdu_pld_size = max_pld_size; ++ ++ /* update scb release size */ ++ brcms_c_scb_ampdu_update_config_all(ampdu); ++ ++ /* ++ * compute a new dma xfer rate for max_mpdu @ max mcs. ++ * This is the minimum dma rate that can achieve no ++ * underflow condition for the current mpdu size. ++ * ++ * note : we divide/multiply by 100 to avoid integer overflows ++ */ ++ fifo->dmaxferrate = ++ (((phy_rate / 100) * ++ (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) ++ / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; ++ ++ BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; " ++ "pre-load size %d\n", ++ fifo->dmaxferrate, fifo->ampdu_pld_size); ++ } else { ++ ++ /* decrease ampdu size */ ++ if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) { ++ if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255) ++ fifo->mcs2ampdu_table[FFPLD_MAX_MCS] = ++ AMPDU_NUM_MPDU_LEGACY - 1; ++ else ++ fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1; ++ ++ /* recompute the table */ ++ brcms_c_ffpld_calc_mcs2ampdu_table(ampdu, fid); ++ ++ /* update scb release size */ ++ brcms_c_scb_ampdu_update_config_all(ampdu); ++ } ++ } ++ fifo->accum_txfunfl = 0; ++ return 0; ++} ++ ++void ++brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, ++ u8 ba_wsize, /* negotiated ba window size (in pdu) */ ++ uint max_rx_ampdu_bytes) /* from ht_cap in beacon */ ++{ ++ struct scb_ampdu *scb_ampdu; ++ struct scb_ampdu_tid_ini *ini; ++ struct ampdu_info *ampdu = wlc->ampdu; ++ struct scb *scb = &wlc->pri_scb; ++ scb_ampdu = &scb->scb_ampdu; ++ ++ if (!ampdu->ini_enable[tid]) { ++ wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n", ++ __func__, tid); ++ return; ++ } ++ ++ ini = &scb_ampdu->ini[tid]; ++ ini->tid = tid; ++ ini->scb = scb_ampdu->scb; ++ ini->ba_wsize = ba_wsize; ++ scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes; ++} ++ ++int ++brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, ++ struct sk_buff **pdu, int prec) ++{ ++ struct brcms_c_info *wlc; ++ struct sk_buff *p, *pkt[AMPDU_MAX_MPDU]; ++ u8 tid, ndelim; ++ int err = 0; ++ u8 preamble_type = BRCMS_GF_PREAMBLE; ++ u8 fbr_preamble_type = BRCMS_GF_PREAMBLE; ++ u8 rts_preamble_type = BRCMS_LONG_PREAMBLE; ++ u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE; ++ ++ bool rr = true, fbr = false; ++ uint i, count = 0, fifo, seg_cnt = 0; ++ u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0; ++ u32 ampdu_len, max_ampdu_bytes = 0; ++ struct d11txh *txh = NULL; ++ u8 *plcp; ++ struct ieee80211_hdr *h; ++ struct scb *scb; ++ struct scb_ampdu *scb_ampdu; ++ struct scb_ampdu_tid_ini *ini; ++ u8 mcs = 0; ++ bool use_rts = false, use_cts = false; ++ u32 rspec = 0, rspec_fallback = 0; ++ u32 rts_rspec = 0, rts_rspec_fallback = 0; ++ u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; ++ struct ieee80211_rts *rts; ++ u8 rr_retry_limit; ++ struct brcms_fifo_info *f; ++ bool fbr_iscck; ++ struct ieee80211_tx_info *tx_info; ++ u16 qlen; ++ struct wiphy *wiphy; ++ ++ wlc = ampdu->wlc; ++ wiphy = wlc->wiphy; ++ p = *pdu; ++ ++ tid = (u8) (p->priority); ++ ++ f = ampdu->fifo_tb + prio2fifo[tid]; ++ ++ scb = &wlc->pri_scb; ++ scb_ampdu = &scb->scb_ampdu; ++ ini = &scb_ampdu->ini[tid]; ++ ++ /* Let pressure continue to build ... */ ++ qlen = pktq_plen(&qi->q, prec); ++ if (ini->tx_in_transit > 0 && ++ qlen < min(scb_ampdu->max_pdu, ini->ba_wsize)) ++ /* Collect multiple MPDU's to be sent in the next AMPDU */ ++ return -EBUSY; ++ ++ /* at this point we intend to transmit an AMPDU */ ++ rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; ++ ampdu_len = 0; ++ dma_len = 0; ++ while (p) { ++ struct ieee80211_tx_rate *txrate; ++ ++ tx_info = IEEE80211_SKB_CB(p); ++ txrate = tx_info->status.rates; ++ ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ err = brcms_c_prep_pdu(wlc, p, &fifo); ++ } else { ++ wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__); ++ *pdu = NULL; ++ err = 0; ++ break; ++ } ++ ++ if (err) { ++ if (err == -EBUSY) { ++ wiphy_err(wiphy, "wl%d: sendampdu: " ++ "prep_xdu retry; seq 0x%x\n", ++ wlc->pub->unit, seq); ++ *pdu = p; ++ break; ++ } ++ ++ /* error in the packet; reject it */ ++ wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu " ++ "rejected; seq 0x%x\n", wlc->pub->unit, seq); ++ *pdu = NULL; ++ break; ++ } ++ ++ /* pkt is good to be aggregated */ ++ txh = (struct d11txh *) p->data; ++ plcp = (u8 *) (txh + 1); ++ h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); ++ seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; ++ index = TX_SEQ_TO_INDEX(seq); ++ ++ /* check mcl fields and test whether it can be agg'd */ ++ mcl = le16_to_cpu(txh->MacTxControlLow); ++ mcl &= ~TXC_AMPDU_MASK; ++ fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3); ++ txh->PreloadSize = 0; /* always default to 0 */ ++ ++ /* Handle retry limits */ ++ if (txrate[0].count <= rr_retry_limit) { ++ txrate[0].count++; ++ rr = true; ++ fbr = false; ++ } else { ++ fbr = true; ++ rr = false; ++ txrate[1].count++; ++ } ++ ++ /* extract the length info */ ++ len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) ++ : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); ++ ++ /* retrieve null delimiter count */ ++ ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; ++ seg_cnt += 1; ++ ++ BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n", ++ wlc->pub->unit, count, len); ++ ++ /* ++ * aggregateable mpdu. For ucode/hw agg, ++ * test whether need to break or change the epoch ++ */ ++ if (count == 0) { ++ mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT); ++ /* refill the bits since might be a retx mpdu */ ++ mcl |= TXC_STARTMSDU; ++ rts = (struct ieee80211_rts *)&txh->rts_frame; ++ ++ if (ieee80211_is_rts(rts->frame_control)) { ++ mcl |= TXC_SENDRTS; ++ use_rts = true; ++ } ++ if (ieee80211_is_cts(rts->frame_control)) { ++ mcl |= TXC_SENDCTS; ++ use_cts = true; ++ } ++ } else { ++ mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT); ++ mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS); ++ } ++ ++ len = roundup(len, 4); ++ ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN); ++ ++ dma_len += (u16) brcmu_pkttotlen(p); ++ ++ BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d" ++ " seg_cnt %d null delim %d\n", ++ wlc->pub->unit, ampdu_len, seg_cnt, ndelim); ++ ++ txh->MacTxControlLow = cpu_to_le16(mcl); ++ ++ /* this packet is added */ ++ pkt[count++] = p; ++ ++ /* patch the first MPDU */ ++ if (count == 1) { ++ u8 plcp0, plcp3, is40, sgi; ++ struct ieee80211_sta *sta; ++ ++ sta = tx_info->control.sta; ++ ++ if (rr) { ++ plcp0 = plcp[0]; ++ plcp3 = plcp[3]; ++ } else { ++ plcp0 = txh->FragPLCPFallback[0]; ++ plcp3 = txh->FragPLCPFallback[3]; ++ ++ } ++ is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0; ++ sgi = plcp3_issgi(plcp3) ? 1 : 0; ++ mcs = plcp0 & ~MIMO_PLCP_40MHZ; ++ max_ampdu_bytes = ++ min(scb_ampdu->max_rx_ampdu_bytes, ++ ampdu->max_txlen[mcs][is40][sgi]); ++ ++ if (is40) ++ mimo_ctlchbw = ++ CHSPEC_SB_UPPER(wlc_phy_chanspec_get( ++ wlc->band->pi)) ++ ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; ++ ++ /* rebuild the rspec and rspec_fallback */ ++ rspec = RSPEC_MIMORATE; ++ rspec |= plcp[0] & ~MIMO_PLCP_40MHZ; ++ if (plcp[0] & MIMO_PLCP_40MHZ) ++ rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); ++ ++ if (fbr_iscck) /* CCK */ ++ rspec_fallback = cck_rspec(cck_phy2mac_rate ++ (txh->FragPLCPFallback[0])); ++ else { /* MIMO */ ++ rspec_fallback = RSPEC_MIMORATE; ++ rspec_fallback |= ++ txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ; ++ if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ) ++ rspec_fallback |= ++ (PHY_TXC1_BW_40MHZ << ++ RSPEC_BW_SHIFT); ++ } ++ ++ if (use_rts || use_cts) { ++ rts_rspec = ++ brcms_c_rspec_to_rts_rspec(wlc, ++ rspec, false, mimo_ctlchbw); ++ rts_rspec_fallback = ++ brcms_c_rspec_to_rts_rspec(wlc, ++ rspec_fallback, false, mimo_ctlchbw); ++ } ++ } ++ ++ /* if (first mpdu for host agg) */ ++ /* test whether to add more */ ++ if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) && ++ (count == f->mcs2ampdu_table[mcs])) { ++ BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping" ++ " ampdu at %d for mcs %d\n", ++ wlc->pub->unit, count, mcs); ++ break; ++ } ++ ++ if (count == scb_ampdu->max_pdu) ++ break; ++ ++ /* ++ * check to see if the next pkt is ++ * a candidate for aggregation ++ */ ++ p = pktq_ppeek(&qi->q, prec); ++ /* tx_info must be checked with current p */ ++ tx_info = IEEE80211_SKB_CB(p); ++ ++ if (p) { ++ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && ++ ((u8) (p->priority) == tid)) { ++ ++ plen = brcmu_pkttotlen(p) + ++ AMPDU_MAX_MPDU_OVERHEAD; ++ plen = max(scb_ampdu->min_len, plen); ++ ++ if ((plen + ampdu_len) > max_ampdu_bytes) { ++ p = NULL; ++ continue; ++ } ++ ++ /* ++ * check if there are enough ++ * descriptors available ++ */ ++ if (*wlc->core->txavail[fifo] <= seg_cnt + 1) { ++ wiphy_err(wiphy, "%s: No fifo space " ++ "!!\n", __func__); ++ p = NULL; ++ continue; ++ } ++ p = brcmu_pktq_pdeq(&qi->q, prec); ++ } else { ++ p = NULL; ++ } ++ } ++ } /* end while(p) */ ++ ++ ini->tx_in_transit += count; ++ ++ if (count) { ++ /* patch up the last txh */ ++ txh = (struct d11txh *) pkt[count - 1]->data; ++ mcl = le16_to_cpu(txh->MacTxControlLow); ++ mcl &= ~TXC_AMPDU_MASK; ++ mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT); ++ txh->MacTxControlLow = cpu_to_le16(mcl); ++ ++ /* remove the null delimiter after last mpdu */ ++ ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; ++ txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0; ++ ampdu_len -= ndelim * AMPDU_DELIMITER_LEN; ++ ++ /* remove the pad len from last mpdu */ ++ fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0); ++ len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) ++ : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); ++ ampdu_len -= roundup(len, 4) - len; ++ ++ /* patch up the first txh & plcp */ ++ txh = (struct d11txh *) pkt[0]->data; ++ plcp = (u8 *) (txh + 1); ++ ++ BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len); ++ /* mark plcp to indicate ampdu */ ++ BRCMS_SET_MIMO_PLCP_AMPDU(plcp); ++ ++ /* reset the mixed mode header durations */ ++ if (txh->MModeLen) { ++ u16 mmodelen = ++ brcms_c_calc_lsig_len(wlc, rspec, ampdu_len); ++ txh->MModeLen = cpu_to_le16(mmodelen); ++ preamble_type = BRCMS_MM_PREAMBLE; ++ } ++ if (txh->MModeFbrLen) { ++ u16 mmfbrlen = ++ brcms_c_calc_lsig_len(wlc, rspec_fallback, ++ ampdu_len); ++ txh->MModeFbrLen = cpu_to_le16(mmfbrlen); ++ fbr_preamble_type = BRCMS_MM_PREAMBLE; ++ } ++ ++ /* set the preload length */ ++ if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) { ++ dma_len = min(dma_len, f->ampdu_pld_size); ++ txh->PreloadSize = cpu_to_le16(dma_len); ++ } else ++ txh->PreloadSize = 0; ++ ++ mch = le16_to_cpu(txh->MacTxControlHigh); ++ ++ /* update RTS dur fields */ ++ if (use_rts || use_cts) { ++ u16 durid; ++ rts = (struct ieee80211_rts *)&txh->rts_frame; ++ if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) == ++ TXC_PREAMBLE_RTS_MAIN_SHORT) ++ rts_preamble_type = BRCMS_SHORT_PREAMBLE; ++ ++ if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) == ++ TXC_PREAMBLE_RTS_FB_SHORT) ++ rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE; ++ ++ durid = ++ brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec, ++ rspec, rts_preamble_type, ++ preamble_type, ampdu_len, ++ true); ++ rts->duration = cpu_to_le16(durid); ++ durid = brcms_c_compute_rtscts_dur(wlc, use_cts, ++ rts_rspec_fallback, ++ rspec_fallback, ++ rts_fbr_preamble_type, ++ fbr_preamble_type, ++ ampdu_len, true); ++ txh->RTSDurFallback = cpu_to_le16(durid); ++ /* set TxFesTimeNormal */ ++ txh->TxFesTimeNormal = rts->duration; ++ /* set fallback rate version of TxFesTimeNormal */ ++ txh->TxFesTimeFallback = txh->RTSDurFallback; ++ } ++ ++ /* set flag and plcp for fallback rate */ ++ if (fbr) { ++ mch |= TXC_AMPDU_FBR; ++ txh->MacTxControlHigh = cpu_to_le16(mch); ++ BRCMS_SET_MIMO_PLCP_AMPDU(plcp); ++ BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback); ++ } ++ ++ BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n", ++ wlc->pub->unit, count, ampdu_len); ++ ++ /* inform rate_sel if it this is a rate probe pkt */ ++ frameid = le16_to_cpu(txh->TxFrameID); ++ if (frameid & TXFID_RATE_PROBE_MASK) ++ wiphy_err(wiphy, "%s: XXX what to do with " ++ "TXFID_RATE_PROBE_MASK!?\n", __func__); ++ ++ for (i = 0; i < count; i++) ++ brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1), ++ ampdu->txpkt_weight); ++ ++ } ++ /* endif (count) */ ++ return err; ++} ++ ++static void ++brcms_c_ampdu_rate_status(struct brcms_c_info *wlc, ++ struct ieee80211_tx_info *tx_info, ++ struct tx_status *txs, u8 mcs) ++{ ++ struct ieee80211_tx_rate *txrate = tx_info->status.rates; ++ int i; ++ ++ /* clear the rest of the rates */ ++ for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) { ++ txrate[i].idx = -1; ++ txrate[i].count = 0; ++ } ++} ++ ++static void ++brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, ++ struct sk_buff *p, struct tx_status *txs, ++ u32 s1, u32 s2) ++{ ++ struct scb_ampdu *scb_ampdu; ++ struct brcms_c_info *wlc = ampdu->wlc; ++ struct scb_ampdu_tid_ini *ini; ++ u8 bitmap[8], queue, tid; ++ struct d11txh *txh; ++ u8 *plcp; ++ struct ieee80211_hdr *h; ++ u16 seq, start_seq = 0, bindex, index, mcl; ++ u8 mcs = 0; ++ bool ba_recd = false, ack_recd = false; ++ u8 suc_mpdu = 0, tot_mpdu = 0; ++ uint supr_status; ++ bool update_rate = true, retry = true, tx_error = false; ++ u16 mimoantsel = 0; ++ u8 antselid = 0; ++ u8 retry_limit, rr_retry_limit; ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p); ++ struct wiphy *wiphy = wlc->wiphy; ++ ++#ifdef BCMDBG ++ u8 hole[AMPDU_MAX_MPDU]; ++ memset(hole, 0, sizeof(hole)); ++#endif ++ ++ scb_ampdu = &scb->scb_ampdu; ++ tid = (u8) (p->priority); ++ ++ ini = &scb_ampdu->ini[tid]; ++ retry_limit = ampdu->retry_limit_tid[tid]; ++ rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; ++ memset(bitmap, 0, sizeof(bitmap)); ++ queue = txs->frameid & TXFID_QUEUE_MASK; ++ supr_status = txs->status & TX_STATUS_SUPR_MASK; ++ ++ if (txs->status & TX_STATUS_ACK_RCV) { ++ if (TX_STATUS_SUPR_UF == supr_status) ++ update_rate = false; ++ ++ WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE)); ++ start_seq = txs->sequence >> SEQNUM_SHIFT; ++ bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >> ++ TX_STATUS_BA_BMAP03_SHIFT; ++ ++ WARN_ON(s1 & TX_STATUS_INTERMEDIATE); ++ WARN_ON(!(s1 & TX_STATUS_AMPDU)); ++ ++ bitmap[0] |= ++ (s1 & TX_STATUS_BA_BMAP47_MASK) << ++ TX_STATUS_BA_BMAP47_SHIFT; ++ bitmap[1] = (s1 >> 8) & 0xff; ++ bitmap[2] = (s1 >> 16) & 0xff; ++ bitmap[3] = (s1 >> 24) & 0xff; ++ ++ bitmap[4] = s2 & 0xff; ++ bitmap[5] = (s2 >> 8) & 0xff; ++ bitmap[6] = (s2 >> 16) & 0xff; ++ bitmap[7] = (s2 >> 24) & 0xff; ++ ++ ba_recd = true; ++ } else { ++ if (supr_status) { ++ update_rate = false; ++ if (supr_status == TX_STATUS_SUPR_BADCH) { ++ wiphy_err(wiphy, "%s: Pkt tx suppressed, " ++ "illegal channel possibly %d\n", ++ __func__, CHSPEC_CHANNEL( ++ wlc->default_bss->chanspec)); ++ } else { ++ if (supr_status != TX_STATUS_SUPR_FRAG) ++ wiphy_err(wiphy, "%s:" ++ "supr_status 0x%x\n", ++ __func__, supr_status); ++ } ++ /* no need to retry for badch; will fail again */ ++ if (supr_status == TX_STATUS_SUPR_BADCH || ++ supr_status == TX_STATUS_SUPR_EXPTIME) { ++ retry = false; ++ } else if (supr_status == TX_STATUS_SUPR_EXPTIME) { ++ /* TX underflow: ++ * try tuning pre-loading or ampdu size ++ */ ++ } else if (supr_status == TX_STATUS_SUPR_FRAG) { ++ /* ++ * if there were underflows, but pre-loading ++ * is not active, notify rate adaptation. ++ */ ++ if (brcms_c_ffpld_check_txfunfl(wlc, ++ prio2fifo[tid]) > 0) ++ tx_error = true; ++ } ++ } else if (txs->phyerr) { ++ update_rate = false; ++ wiphy_err(wiphy, "wl%d: ampdu tx phy " ++ "error (0x%x)\n", wlc->pub->unit, ++ txs->phyerr); ++ ++ if (brcm_msg_level & LOG_ERROR_VAL) { ++ brcmu_prpkt("txpkt (AMPDU)", p); ++ brcms_c_print_txdesc((struct d11txh *) p->data); ++ } ++ brcms_c_print_txstatus(txs); ++ } ++ } ++ ++ /* loop through all pkts and retry if not acked */ ++ while (p) { ++ tx_info = IEEE80211_SKB_CB(p); ++ txh = (struct d11txh *) p->data; ++ mcl = le16_to_cpu(txh->MacTxControlLow); ++ plcp = (u8 *) (txh + 1); ++ h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); ++ seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; ++ ++ if (tot_mpdu == 0) { ++ mcs = plcp[0] & MIMO_PLCP_MCS_MASK; ++ mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel); ++ } ++ ++ index = TX_SEQ_TO_INDEX(seq); ++ ack_recd = false; ++ if (ba_recd) { ++ bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX); ++ BCMMSG(wlc->wiphy, "tid %d seq %d," ++ " start_seq %d, bindex %d set %d, index %d\n", ++ tid, seq, start_seq, bindex, ++ isset(bitmap, bindex), index); ++ /* if acked then clear bit and free packet */ ++ if ((bindex < AMPDU_TX_BA_MAX_WSIZE) ++ && isset(bitmap, bindex)) { ++ ini->tx_in_transit--; ++ ini->txretry[index] = 0; ++ ++ /* ++ * ampdu_ack_len: ++ * number of acked aggregated frames ++ */ ++ /* ampdu_len: number of aggregated frames */ ++ brcms_c_ampdu_rate_status(wlc, tx_info, txs, ++ mcs); ++ tx_info->flags |= IEEE80211_TX_STAT_ACK; ++ tx_info->flags |= IEEE80211_TX_STAT_AMPDU; ++ tx_info->status.ampdu_ack_len = ++ tx_info->status.ampdu_len = 1; ++ ++ skb_pull(p, D11_PHY_HDR_LEN); ++ skb_pull(p, D11_TXH_LEN); ++ ++ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, ++ p); ++ ack_recd = true; ++ suc_mpdu++; ++ } ++ } ++ /* either retransmit or send bar if ack not recd */ ++ if (!ack_recd) { ++ struct ieee80211_tx_rate *txrate = ++ tx_info->status.rates; ++ if (retry && (txrate[0].count < (int)retry_limit)) { ++ ini->txretry[index]++; ++ ini->tx_in_transit--; ++ /* ++ * Use high prededence for retransmit to ++ * give some punch ++ */ ++ /* brcms_c_txq_enq(wlc, scb, p, ++ * BRCMS_PRIO_TO_PREC(tid)); */ ++ brcms_c_txq_enq(wlc, scb, p, ++ BRCMS_PRIO_TO_HI_PREC(tid)); ++ } else { ++ /* Retry timeout */ ++ ini->tx_in_transit--; ++ ieee80211_tx_info_clear_status(tx_info); ++ tx_info->status.ampdu_ack_len = 0; ++ tx_info->status.ampdu_len = 1; ++ tx_info->flags |= ++ IEEE80211_TX_STAT_AMPDU_NO_BACK; ++ skb_pull(p, D11_PHY_HDR_LEN); ++ skb_pull(p, D11_TXH_LEN); ++ wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_" ++ "transit %d\n", "AMPDU status", seq, ++ ini->tx_in_transit); ++ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, ++ p); ++ } ++ } ++ tot_mpdu++; ++ ++ /* break out if last packet of ampdu */ ++ if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) == ++ TXC_AMPDU_LAST) ++ break; ++ ++ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); ++ } ++ brcms_c_send_q(wlc); ++ ++ /* update rate state */ ++ antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel); ++ ++ brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); ++} ++ ++void ++brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, ++ struct sk_buff *p, struct tx_status *txs) ++{ ++ struct scb_ampdu *scb_ampdu; ++ struct brcms_c_info *wlc = ampdu->wlc; ++ struct scb_ampdu_tid_ini *ini; ++ u32 s1 = 0, s2 = 0; ++ struct ieee80211_tx_info *tx_info; ++ ++ tx_info = IEEE80211_SKB_CB(p); ++ ++ /* BMAC_NOTE: For the split driver, second level txstatus comes later ++ * So if the ACK was received then wait for the second level else just ++ * call the first one ++ */ ++ if (txs->status & TX_STATUS_ACK_RCV) { ++ u8 status_delay = 0; ++ ++ /* wait till the next 8 bytes of txstatus is available */ ++ while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) { ++ udelay(1); ++ status_delay++; ++ if (status_delay > 10) ++ return; /* error condition */ ++ } ++ ++ s2 = R_REG(&wlc->regs->frmtxstatus2); ++ } ++ ++ if (scb) { ++ scb_ampdu = &scb->scb_ampdu; ++ ini = &scb_ampdu->ini[p->priority]; ++ brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2); ++ } else { ++ /* loop through all pkts and free */ ++ u8 queue = txs->frameid & TXFID_QUEUE_MASK; ++ struct d11txh *txh; ++ u16 mcl; ++ while (p) { ++ tx_info = IEEE80211_SKB_CB(p); ++ txh = (struct d11txh *) p->data; ++ mcl = le16_to_cpu(txh->MacTxControlLow); ++ brcmu_pkt_buf_free_skb(p); ++ /* break out if last packet of ampdu */ ++ if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) == ++ TXC_AMPDU_LAST) ++ break; ++ p = dma_getnexttxp(wlc->hw->di[queue], ++ DMA_RANGE_TRANSMITTED); ++ } ++ brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); ++ } ++} ++ ++void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc) ++{ ++ char template[T_RAM_ACCESS_SZ * 2]; ++ ++ /* driver needs to write the ta in the template; ta is at offset 16 */ ++ memset(template, 0, sizeof(template)); ++ memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN); ++ brcms_b_write_template_ram(wlc->hw, (T_BA_TPL_BASE + 16), ++ (T_RAM_ACCESS_SZ * 2), ++ template); ++} ++ ++bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid) ++{ ++ return wlc->ampdu->ini_enable[tid]; ++} ++ ++void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu) ++{ ++ struct brcms_c_info *wlc = ampdu->wlc; ++ ++ /* ++ * Extend ucode internal watchdog timer to ++ * match larger received frames ++ */ ++ if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) == ++ IEEE80211_HT_MAX_AMPDU_64K) { ++ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX); ++ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX); ++ } else { ++ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF); ++ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF); ++ } ++} ++ ++/* ++ * callback function that helps flushing ampdu packets from a priority queue ++ */ ++static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu); ++ struct cb_del_ampdu_pars *ampdu_pars = ++ (struct cb_del_ampdu_pars *)arg_a; ++ bool rc; ++ ++ rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false; ++ rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL || ++ tx_info->control.sta == ampdu_pars->sta); ++ rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid); ++ return rc; ++} ++ ++/* ++ * callback function that helps invalidating ampdu packets in a DMA queue ++ */ ++static void dma_cb_fn_ampdu(void *txi, void *arg_a) ++{ ++ struct ieee80211_sta *sta = arg_a; ++ struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi; ++ ++ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && ++ (tx_info->control.sta == sta || sta == NULL)) ++ tx_info->control.sta = NULL; ++} ++ ++/* ++ * When a remote party is no longer available for ampdu communication, any ++ * pending tx ampdu packets in the driver have to be flushed. ++ */ ++void brcms_c_ampdu_flush(struct brcms_c_info *wlc, ++ struct ieee80211_sta *sta, u16 tid) ++{ ++ struct brcms_txq_info *qi = wlc->pkt_queue; ++ struct pktq *pq = &qi->q; ++ int prec; ++ struct cb_del_ampdu_pars ampdu_pars; ++ ++ ampdu_pars.sta = sta; ++ ampdu_pars.tid = tid; ++ for (prec = 0; prec < pq->num_prec; prec++) ++ brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt, ++ (void *)&du_pars); ++ brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h.orig 2011-11-09 13:46:58.240800696 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h 2011-11-09 13:47:16.992566265 -0500 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_AMPDU_H_ ++#define _BRCM_AMPDU_H_ ++ ++extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc); ++extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu); ++extern int brcms_c_sendampdu(struct ampdu_info *ampdu, ++ struct brcms_txq_info *qi, ++ struct sk_buff **aggp, int prec); ++extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, ++ struct sk_buff *p, struct tx_status *txs); ++extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc); ++extern void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu); ++ ++#endif /* _BRCM_AMPDU_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.c.orig 2011-11-09 13:46:58.240800696 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.c 2011-11-09 13:47:16.992566265 -0500 +@@ -0,0 +1,307 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++ ++#include "types.h" ++#include "main.h" ++#include "phy_shim.h" ++#include "antsel.h" ++ ++#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ ++#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ ++#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ ++#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ ++#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ ++#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ ++ ++/* useful macros */ ++#define BRCMS_ANTSEL_11N_0(ant) ((((ant) & ANT_SELCFG_MASK) >> 4) & 0xf) ++#define BRCMS_ANTSEL_11N_1(ant) (((ant) & ANT_SELCFG_MASK) & 0xf) ++#define BRCMS_ANTIDX_11N(ant) (((BRCMS_ANTSEL_11N_0(ant)) << 2) +\ ++ (BRCMS_ANTSEL_11N_1(ant))) ++#define BRCMS_ANT_ISAUTO_11N(ant) (((ant) & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) ++#define BRCMS_ANTSEL_11N(ant) ((ant) & ANT_SELCFG_MASK) ++ ++/* antenna switch */ ++/* defines for no boardlevel antenna diversity */ ++#define ANT_SELCFG_DEF_2x2 0x01 /* default antenna configuration */ ++ ++/* 2x3 antdiv defines and tables for GPIO communication */ ++#define ANT_SELCFG_NUM_2x3 3 ++#define ANT_SELCFG_DEF_2x3 0x01 /* default antenna configuration */ ++ ++/* 2x4 antdiv rev4 defines and tables for GPIO communication */ ++#define ANT_SELCFG_NUM_2x4 4 ++#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */ ++ ++static const u16 mimo_2x4_div_antselpat_tbl[] = { ++ 0, 0, 0x9, 0xa, /* ant0: 0 ant1: 2,3 */ ++ 0, 0, 0x5, 0x6, /* ant0: 1 ant1: 2,3 */ ++ 0, 0, 0, 0, /* n.a. */ ++ 0, 0, 0, 0 /* n.a. */ ++}; ++ ++static const u8 mimo_2x4_div_antselid_tbl[16] = { ++ 0, 0, 0, 0, 0, 2, 3, 0, ++ 0, 0, 1, 0, 0, 0, 0, 0 /* pat to antselid */ ++}; ++ ++static const u16 mimo_2x3_div_antselpat_tbl[] = { ++ 16, 0, 1, 16, /* ant0: 0 ant1: 1,2 */ ++ 16, 16, 16, 16, /* n.a. */ ++ 16, 2, 16, 16, /* ant0: 2 ant1: 1 */ ++ 16, 16, 16, 16 /* n.a. */ ++}; ++ ++static const u8 mimo_2x3_div_antselid_tbl[16] = { ++ 0, 1, 2, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ ++}; ++ ++/* boardlevel antenna selection: init antenna selection structure */ ++static void ++brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel, ++ bool auto_sel) ++{ ++ if (asi->antsel_type == ANTSEL_2x3) { ++ u8 antcfg_def = ANT_SELCFG_DEF_2x3 | ++ ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0); ++ antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def; ++ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def; ++ antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def; ++ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def; ++ antsel->num_antcfg = ANT_SELCFG_NUM_2x3; ++ ++ } else if (asi->antsel_type == ANTSEL_2x4) { ++ ++ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4; ++ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4; ++ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4; ++ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4; ++ antsel->num_antcfg = ANT_SELCFG_NUM_2x4; ++ ++ } else { /* no antenna selection available */ ++ ++ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2; ++ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2; ++ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2; ++ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2; ++ antsel->num_antcfg = 0; ++ } ++} ++ ++struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) ++{ ++ struct antsel_info *asi; ++ struct si_pub *sih = wlc->hw->sih; ++ ++ asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); ++ if (!asi) ++ return NULL; ++ ++ asi->wlc = wlc; ++ asi->pub = wlc->pub; ++ asi->antsel_type = ANTSEL_NA; ++ asi->antsel_avail = false; ++ asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH); ++ ++ if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) { ++ switch (asi->antsel_antswitch) { ++ case ANTSWITCH_TYPE_1: ++ case ANTSWITCH_TYPE_2: ++ case ANTSWITCH_TYPE_3: ++ /* 4321/2 board with 2x3 switch logic */ ++ asi->antsel_type = ANTSEL_2x3; ++ /* Antenna selection availability */ ++ if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) || ++ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) { ++ asi->antsel_avail = true; ++ } else if ( ++ (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 || ++ (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) { ++ asi->antsel_avail = false; ++ } else { ++ asi->antsel_avail = false; ++ wiphy_err(wlc->wiphy, "antsel_attach: 2o3 " ++ "board cfg invalid\n"); ++ } ++ ++ break; ++ default: ++ break; ++ } ++ } else if ((asi->pub->sromrev == 4) && ++ ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) && ++ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) { ++ /* hack to match old 4321CB2 cards with 2of3 antenna switch */ ++ asi->antsel_type = ANTSEL_2x3; ++ asi->antsel_avail = true; ++ } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) { ++ asi->antsel_type = ANTSEL_2x4; ++ asi->antsel_avail = true; ++ } ++ ++ /* Set the antenna selection type for the low driver */ ++ brcms_b_antsel_type_set(wlc->hw, asi->antsel_type); ++ ++ /* Init (auto/manual) antenna selection */ ++ brcms_c_antsel_init_cfg(asi, &asi->antcfg_11n, true); ++ brcms_c_antsel_init_cfg(asi, &asi->antcfg_cur, true); ++ ++ return asi; ++} ++ ++void brcms_c_antsel_detach(struct antsel_info *asi) ++{ ++ kfree(asi); ++} ++ ++/* ++ * boardlevel antenna selection: ++ * convert ant_cfg to mimo_antsel (ucode interface) ++ */ ++static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg) ++{ ++ u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg)); ++ u16 mimo_antsel = 0; ++ ++ if (asi->antsel_type == ANTSEL_2x4) { ++ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ ++ mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf); ++ return mimo_antsel; ++ ++ } else if (asi->antsel_type == ANTSEL_2x3) { ++ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ ++ mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf); ++ return mimo_antsel; ++ } ++ ++ return mimo_antsel; ++} ++ ++/* boardlevel antenna selection: ucode interface control */ ++static int brcms_c_antsel_cfgupd(struct antsel_info *asi, ++ struct brcms_antselcfg *antsel) ++{ ++ struct brcms_c_info *wlc = asi->wlc; ++ u8 ant_cfg; ++ u16 mimo_antsel; ++ ++ /* 1) Update TX antconfig for all frames that are not unicast data ++ * (aka default TX) ++ */ ++ ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF]; ++ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); ++ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_TXDFLT, mimo_antsel); ++ /* ++ * Update driver stats for currently selected ++ * default tx/rx antenna config ++ */ ++ asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg; ++ ++ /* 2) Update RX antconfig for all frames that are not unicast data ++ * (aka default RX) ++ */ ++ ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF]; ++ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); ++ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_RXDFLT, mimo_antsel); ++ /* ++ * Update driver stats for currently selected ++ * default tx/rx antenna config ++ */ ++ asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg; ++ ++ return 0; ++} ++ ++void brcms_c_antsel_init(struct antsel_info *asi) ++{ ++ if ((asi->antsel_type == ANTSEL_2x3) || ++ (asi->antsel_type == ANTSEL_2x4)) ++ brcms_c_antsel_cfgupd(asi, &asi->antcfg_11n); ++} ++ ++/* boardlevel antenna selection: convert id to ant_cfg */ ++static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id) ++{ ++ u8 antcfg = ANT_SELCFG_DEF_2x2; ++ ++ if (asi->antsel_type == ANTSEL_2x4) { ++ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ ++ antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2)); ++ return antcfg; ++ ++ } else if (asi->antsel_type == ANTSEL_2x3) { ++ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ ++ antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1)); ++ return antcfg; ++ } ++ ++ return antcfg; ++} ++ ++void ++brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel, ++ u8 antselid, u8 fbantselid, u8 *antcfg, ++ u8 *fbantcfg) ++{ ++ u8 ant; ++ ++ /* if use default, assign it and return */ ++ if (usedef) { ++ *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_DEF]; ++ *fbantcfg = *antcfg; ++ return; ++ } ++ ++ if (!sel) { ++ *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; ++ *fbantcfg = *antcfg; ++ ++ } else { ++ ant = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; ++ if ((ant & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) { ++ *antcfg = brcms_c_antsel_id2antcfg(asi, antselid); ++ *fbantcfg = brcms_c_antsel_id2antcfg(asi, fbantselid); ++ } else { ++ *antcfg = ++ asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; ++ *fbantcfg = *antcfg; ++ } ++ } ++ return; ++} ++ ++/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */ ++u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel) ++{ ++ u8 antselid = 0; ++ ++ if (asi->antsel_type == ANTSEL_2x4) { ++ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ ++ antselid = mimo_2x4_div_antselid_tbl[(antsel & 0xf)]; ++ return antselid; ++ ++ } else if (asi->antsel_type == ANTSEL_2x3) { ++ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ ++ antselid = mimo_2x3_div_antselid_tbl[(antsel & 0xf)]; ++ return antselid; ++ } ++ ++ return antselid; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.h.orig 2011-11-09 13:46:58.241800683 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/antsel.h 2011-11-09 13:47:16.993566253 -0500 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_ANTSEL_H_ ++#define _BRCM_ANTSEL_H_ ++ ++extern struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc); ++extern void brcms_c_antsel_detach(struct antsel_info *asi); ++extern void brcms_c_antsel_init(struct antsel_info *asi); ++extern void brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, ++ bool sel, ++ u8 id, u8 fbid, u8 *antcfg, ++ u8 *fbantcfg); ++extern u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel); ++ ++#endif /* _BRCM_ANTSEL_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c.orig 2011-11-09 13:46:58.241800683 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c 2011-11-09 13:47:16.993566253 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2011 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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 /* bug in tracepoint.h, it should include this */ ++ ++#ifndef __CHECKER__ ++#include "mac80211_if.h" ++#define CREATE_TRACE_POINTS ++#include "brcms_trace_events.h" ++#endif +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h.orig 2011-11-09 13:46:58.241800683 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h 2011-11-09 13:47:16.993566253 -0500 +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (c) 2011 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM brcmsmac ++ ++#if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ) ++ ++#define __TRACE_BRCMSMAC_H ++ ++#include ++#include "mac80211_if.h" ++ ++#ifndef CONFIG_BRCMDBG ++#undef TRACE_EVENT ++#define TRACE_EVENT(name, proto, ...) \ ++static inline void trace_ ## name(proto) {} ++#endif ++ ++/* ++ * We define a tracepoint, its arguments, its printk format and its ++ * 'fast binary record' layout. ++ */ ++TRACE_EVENT(brcms_timer, ++ /* TPPROTO is the prototype of the function called by this tracepoint */ ++ TP_PROTO(struct brcms_timer *t), ++ /* ++ * TPARGS(firstarg, p) are the parameters names, same as found in the ++ * prototype. ++ */ ++ TP_ARGS(t), ++ /* ++ * Fast binary tracing: define the trace record via TP_STRUCT__entry(). ++ * You can think about it like a regular C structure local variable ++ * definition. ++ */ ++ TP_STRUCT__entry( ++ __field(uint, ms) ++ __field(uint, set) ++ __field(uint, periodic) ++ ), ++ TP_fast_assign( ++ __entry->ms = t->ms; ++ __entry->set = t->set; ++ __entry->periodic = t->periodic; ++ ), ++ TP_printk( ++ "ms=%u set=%u periodic=%u", ++ __entry->ms, __entry->set, __entry->periodic ++ ) ++); ++ ++TRACE_EVENT(brcms_dpc, ++ TP_PROTO(unsigned long data), ++ TP_ARGS(data), ++ TP_STRUCT__entry( ++ __field(unsigned long, data) ++ ), ++ TP_fast_assign( ++ __entry->data = data; ++ ), ++ TP_printk( ++ "data=%p", ++ (void *)__entry->data ++ ) ++); ++ ++#endif /* __TRACE_BRCMSMAC_H */ ++ ++#ifdef CONFIG_BRCMDBG ++ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#undef TRACE_INCLUDE_FILE ++#define TRACE_INCLUDE_FILE brcms_trace_events ++ ++#include ++ ++#endif /* CONFIG_BRCMDBG */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.c.orig 2011-11-09 13:46:58.242800670 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.c 2011-11-09 13:47:16.994566241 -0500 +@@ -0,0 +1,1591 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++ ++#include ++#include "pub.h" ++#include "phy/phy_hal.h" ++#include "main.h" ++#include "stf.h" ++#include "channel.h" ++ ++/* QDB() macro takes a dB value and converts to a quarter dB value */ ++#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR) ++ ++#define LOCALE_CHAN_01_11 (1<<0) ++#define LOCALE_CHAN_12_13 (1<<1) ++#define LOCALE_CHAN_14 (1<<2) ++#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */ ++#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */ ++#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */ ++#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */ ++#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */ ++#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */ ++#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */ ++#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */ ++#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */ ++#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */ ++#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */ ++#define LOCALE_CHAN_52_140_ALL (1<<14) ++#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */ ++ ++#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \ ++ LOCALE_SET_5G_LOW2 | \ ++ LOCALE_SET_5G_LOW3) ++#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3) ++#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2) ++#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \ ++ LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1) ++#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3) ++#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4 ++ ++#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \ ++ LOCALE_CHAN_12_13 | \ ++ LOCALE_CHAN_14) ++ ++#define LOCALE_RADAR_SET_NONE 0 ++#define LOCALE_RADAR_SET_1 1 ++ ++#define LOCALE_RESTRICTED_NONE 0 ++#define LOCALE_RESTRICTED_SET_2G_SHORT 1 ++#define LOCALE_RESTRICTED_CHAN_165 2 ++#define LOCALE_CHAN_ALL_5G 3 ++#define LOCALE_RESTRICTED_JAPAN_LEGACY 4 ++#define LOCALE_RESTRICTED_11D_2G 5 ++#define LOCALE_RESTRICTED_11D_5G 6 ++#define LOCALE_RESTRICTED_LOW_HI 7 ++#define LOCALE_RESTRICTED_12_13_14 8 ++ ++#define LOCALE_2G_IDX_i 0 ++#define LOCALE_5G_IDX_11 0 ++#define LOCALE_MIMO_IDX_bn 0 ++#define LOCALE_MIMO_IDX_11n 0 ++ ++/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */ ++#define BRCMS_MAXPWR_TBL_SIZE 6 ++/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */ ++#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14 ++ ++/* power level in group of 2.4GHz band channels: ++ * maxpwr[0] - CCK channels [1] ++ * maxpwr[1] - CCK channels [2-10] ++ * maxpwr[2] - CCK channels [11-14] ++ * maxpwr[3] - OFDM channels [1] ++ * maxpwr[4] - OFDM channels [2-10] ++ * maxpwr[5] - OFDM channels [11-14] ++ */ ++ ++/* maxpwr mapping to 5GHz band channels: ++ * maxpwr[0] - channels [34-48] ++ * maxpwr[1] - channels [52-60] ++ * maxpwr[2] - channels [62-64] ++ * maxpwr[3] - channels [100-140] ++ * maxpwr[4] - channels [149-165] ++ */ ++#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */ ++ ++#define LC(id) LOCALE_MIMO_IDX_ ## id ++ ++#define LC_2G(id) LOCALE_2G_IDX_ ## id ++ ++#define LC_5G(id) LOCALE_5G_IDX_ ## id ++ ++#define LOCALES(band2, band5, mimo2, mimo5) \ ++ {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)} ++ ++/* macro to get 2.4 GHz channel group index for tx power */ ++#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2)) ++#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5)) ++ ++/* macro to get 5 GHz channel group index for tx power */ ++#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \ ++ (((c) < 62) ? 1 : \ ++ (((c) < 100) ? 2 : \ ++ (((c) < 149) ? 3 : 4)))) ++ ++#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU) ++ ++struct brcms_cm_band { ++ /* struct locale_info flags */ ++ u8 locale_flags; ++ /* List of valid channels in the country */ ++ struct brcms_chanvec valid_channels; ++ /* List of restricted use channels */ ++ const struct brcms_chanvec *restricted_channels; ++ /* List of radar sensitive channels */ ++ const struct brcms_chanvec *radar_channels; ++ u8 PAD[8]; ++}; ++ ++ /* locale per-channel tx power limits for MIMO frames ++ * maxpwr arrays are index by channel for 2.4 GHz limits, and ++ * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel) ++ */ ++struct locale_mimo_info { ++ /* tx 20 MHz power limits, qdBm units */ ++ s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE]; ++ /* tx 40 MHz power limits, qdBm units */ ++ s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE]; ++ u8 flags; ++}; ++ ++/* Country names and abbreviations with locale defined from ISO 3166 */ ++struct country_info { ++ const u8 locale_2G; /* 2.4G band locale */ ++ const u8 locale_5G; /* 5G band locale */ ++ const u8 locale_mimo_2G; /* 2.4G mimo info */ ++ const u8 locale_mimo_5G; /* 5G mimo info */ ++}; ++ ++struct brcms_cm_info { ++ struct brcms_pub *pub; ++ struct brcms_c_info *wlc; ++ char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */ ++ uint srom_regrev; /* Regulatory Rev for the SROM ccode */ ++ const struct country_info *country; /* current country def */ ++ char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */ ++ uint regrev; /* current Regulatory Revision */ ++ char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */ ++ /* per-band state (one per phy/radio) */ ++ struct brcms_cm_band bandstate[MAXBANDS]; ++ /* quiet channels currently for radar sensitivity or 11h support */ ++ /* channels on which we cannot transmit */ ++ struct brcms_chanvec quiet_channels; ++}; ++ ++/* locale channel and power info. */ ++struct locale_info { ++ u32 valid_channels; ++ /* List of radar sensitive channels */ ++ u8 radar_channels; ++ /* List of channels used only if APs are detected */ ++ u8 restricted_channels; ++ /* Max tx pwr in qdBm for each sub-band */ ++ s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE]; ++ /* Country IE advertised max tx pwr in dBm per sub-band */ ++ s8 pub_maxpwr[BAND_5G_PWR_LVLS]; ++ u8 flags; ++}; ++ ++/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */ ++ ++/* ++ * Some common channel sets ++ */ ++ ++/* No channels */ ++static const struct brcms_chanvec chanvec_none = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* All 2.4 GHz HW channels */ ++static const struct brcms_chanvec chanvec_all_2G = { ++ {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* All 5 GHz HW channels */ ++static const struct brcms_chanvec chanvec_all_5G = { ++ {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11, ++ 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, ++ 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11, ++ 0x11, 0x11, 0x11, 0x01} ++}; ++ ++/* ++ * Radar channel sets ++ */ ++ ++/* Channels 52 - 64, 100 - 140 */ ++static const struct brcms_chanvec radar_set1 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */ ++ 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */ ++ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */ ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* ++ * Restricted channel sets ++ */ ++ ++/* Channels 34, 38, 42, 46 */ ++static const struct brcms_chanvec restricted_set_japan_legacy = { ++ {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* Channels 12, 13 */ ++static const struct brcms_chanvec restricted_set_2g_short = { ++ {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* Channel 165 */ ++static const struct brcms_chanvec restricted_chan_165 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* Channels 36 - 48 & 149 - 165 */ ++static const struct brcms_chanvec restricted_low_hi = { ++ {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* Channels 12 - 14 */ ++static const struct brcms_chanvec restricted_set_12_13_14 = { ++ {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* global memory to provide working buffer for expanded locale */ ++ ++static const struct brcms_chanvec *g_table_radar_set[] = { ++ &chanvec_none, ++ &radar_set1 ++}; ++ ++static const struct brcms_chanvec *g_table_restricted_chan[] = { ++ &chanvec_none, /* restricted_set_none */ ++ &restricted_set_2g_short, ++ &restricted_chan_165, ++ &chanvec_all_5G, ++ &restricted_set_japan_legacy, ++ &chanvec_all_2G, /* restricted_set_11d_2G */ ++ &chanvec_all_5G, /* restricted_set_11d_5G */ ++ &restricted_low_hi, ++ &restricted_set_12_13_14 ++}; ++ ++static const struct brcms_chanvec locale_2g_01_11 = { ++ {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_2g_12_13 = { ++ {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_2g_14 = { ++ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_LOW_JP1 = { ++ {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_LOW_JP2 = { ++ {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_LOW1 = { ++ {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_LOW2 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_LOW3 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_MID1 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_MID2 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_MID3 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_HIGH1 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_HIGH2 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_HIGH3 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_52_140_ALL = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, ++ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, ++ 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_chanvec locale_5g_HIGH4 = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++ 0x11, 0x11, 0x11, 0x11} ++}; ++ ++static const struct brcms_chanvec *g_table_locale_base[] = { ++ &locale_2g_01_11, ++ &locale_2g_12_13, ++ &locale_2g_14, ++ &locale_5g_LOW_JP1, ++ &locale_5g_LOW_JP2, ++ &locale_5g_LOW1, ++ &locale_5g_LOW2, ++ &locale_5g_LOW3, ++ &locale_5g_MID1, ++ &locale_5g_MID2, ++ &locale_5g_MID3, ++ &locale_5g_HIGH1, ++ &locale_5g_HIGH2, ++ &locale_5g_HIGH3, ++ &locale_5g_52_140_ALL, ++ &locale_5g_HIGH4 ++}; ++ ++static void brcms_c_locale_add_channels(struct brcms_chanvec *target, ++ const struct brcms_chanvec *channels) ++{ ++ u8 i; ++ for (i = 0; i < sizeof(struct brcms_chanvec); i++) ++ target->vec[i] |= channels->vec[i]; ++} ++ ++static void brcms_c_locale_get_channels(const struct locale_info *locale, ++ struct brcms_chanvec *channels) ++{ ++ u8 i; ++ ++ memset(channels, 0, sizeof(struct brcms_chanvec)); ++ ++ for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) { ++ if (locale->valid_channels & (1 << i)) ++ brcms_c_locale_add_channels(channels, ++ g_table_locale_base[i]); ++ } ++} ++ ++/* ++ * Locale Definitions - 2.4 GHz ++ */ ++static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */ ++ LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13, ++ LOCALE_RADAR_SET_NONE, ++ LOCALE_RESTRICTED_SET_2G_SHORT, ++ {QDB(19), QDB(19), QDB(19), ++ QDB(19), QDB(19), QDB(19)}, ++ {20, 20, 20, 0}, ++ BRCMS_EIRP ++}; ++ ++/* ++ * Locale Definitions - 5 GHz ++ */ ++static const struct locale_info locale_11 = { ++ /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */ ++ LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165, ++ LOCALE_RADAR_SET_1, ++ LOCALE_RESTRICTED_NONE, ++ {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)}, ++ {23, 23, 23, 30, 30}, ++ BRCMS_EIRP | BRCMS_DFS_EU ++}; ++ ++static const struct locale_info *g_locale_2g_table[] = { ++ &locale_i ++}; ++ ++static const struct locale_info *g_locale_5g_table[] = { ++ &locale_11 ++}; ++ ++/* ++ * MIMO Locale Definitions - 2.4 GHz ++ */ ++static const struct locale_mimo_info locale_bn = { ++ {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), ++ QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), ++ QDB(13), QDB(13), QDB(13)}, ++ {0, 0, QDB(13), QDB(13), QDB(13), ++ QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), ++ QDB(13), 0, 0}, ++ 0 ++}; ++ ++static const struct locale_mimo_info *g_mimo_2g_table[] = { ++ &locale_bn ++}; ++ ++/* ++ * MIMO Locale Definitions - 5 GHz ++ */ ++static const struct locale_mimo_info locale_11n = { ++ { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)}, ++ {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)}, ++ 0 ++}; ++ ++static const struct locale_mimo_info *g_mimo_5g_table[] = { ++ &locale_11n ++}; ++ ++static const struct { ++ char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */ ++ struct country_info country; ++} cntry_locales[] = { ++ { ++ "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */ ++}; ++ ++#ifdef SUPPORT_40MHZ ++/* 20MHz channel info for 40MHz pairing support */ ++struct chan20_info { ++ u8 sb; ++ u8 adj_sbs; ++}; ++ ++/* indicates adjacent channels that are allowed for a 40 Mhz channel and ++ * those that permitted by the HT ++ */ ++struct chan20_info chan20_info[] = { ++ /* 11b/11g */ ++/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, ++/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, ++/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, ++/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, ++/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, ++/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 11 */ {12, (CH_LOWER_SB)}, ++/* 12 */ {13, (CH_LOWER_SB)}, ++/* 13 */ {14, (CH_LOWER_SB)}, ++ ++/* 11a japan high */ ++/* 14 */ {34, (CH_UPPER_SB)}, ++/* 15 */ {38, (CH_LOWER_SB)}, ++/* 16 */ {42, (CH_LOWER_SB)}, ++/* 17 */ {46, (CH_LOWER_SB)}, ++ ++/* 11a usa low */ ++/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)}, ++ ++/* 11a Europe */ ++/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 36 */ {140, (CH_LOWER_SB)}, ++ ++/* 11a usa high, ref5 only */ ++/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */ ++/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)}, ++/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)}, ++/* 41 */ {165, (CH_LOWER_SB)}, ++ ++/* 11a japan */ ++/* 42 */ {184, (CH_UPPER_SB)}, ++/* 43 */ {188, (CH_LOWER_SB)}, ++/* 44 */ {192, (CH_UPPER_SB)}, ++/* 45 */ {196, (CH_LOWER_SB)}, ++/* 46 */ {200, (CH_UPPER_SB)}, ++/* 47 */ {204, (CH_LOWER_SB)}, ++/* 48 */ {208, (CH_UPPER_SB)}, ++/* 49 */ {212, (CH_LOWER_SB)}, ++/* 50 */ {216, (CH_LOWER_SB)} ++}; ++#endif /* SUPPORT_40MHZ */ ++ ++static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx) ++{ ++ if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) ++ return NULL; /* error condition */ ++ ++ return g_locale_2g_table[locale_idx]; ++} ++ ++static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx) ++{ ++ if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) ++ return NULL; /* error condition */ ++ ++ return g_locale_5g_table[locale_idx]; ++} ++ ++static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx) ++{ ++ if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) ++ return NULL; ++ ++ return g_mimo_2g_table[locale_idx]; ++} ++ ++static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx) ++{ ++ if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) ++ return NULL; ++ ++ return g_mimo_5g_table[locale_idx]; ++} ++ ++static int ++brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode, ++ char *mapped_ccode, uint *mapped_regrev) ++{ ++ return false; ++} ++ ++/* Lookup a country info structure from a null terminated country ++ * abbreviation and regrev directly with no translation. ++ */ ++static const struct country_info * ++brcms_c_country_lookup_direct(const char *ccode, uint regrev) ++{ ++ uint size, i; ++ ++ /* Should just return 0 for single locale driver. */ ++ /* Keep it this way in case we add more locales. (for now anyway) */ ++ ++ /* ++ * all other country def arrays are for regrev == 0, so if ++ * regrev is non-zero, fail ++ */ ++ if (regrev > 0) ++ return NULL; ++ ++ /* find matched table entry from country code */ ++ size = ARRAY_SIZE(cntry_locales); ++ for (i = 0; i < size; i++) { ++ if (strcmp(ccode, cntry_locales[i].abbrev) == 0) ++ return &cntry_locales[i].country; ++ } ++ return NULL; ++} ++ ++static const struct country_info * ++brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode, ++ char *mapped_ccode, uint *mapped_regrev) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ const struct country_info *country; ++ uint srom_regrev = wlc_cm->srom_regrev; ++ const char *srom_ccode = wlc_cm->srom_ccode; ++ int mapped; ++ ++ /* check for currently supported ccode size */ ++ if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for " ++ "match\n", wlc->pub->unit, __func__, ccode); ++ return NULL; ++ } ++ ++ /* default mapping is the given ccode and regrev 0 */ ++ strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); ++ *mapped_regrev = 0; ++ ++ /* If the desired country code matches the srom country code, ++ * then the mapped country is the srom regulatory rev. ++ * Otherwise look for an aggregate mapping. ++ */ ++ if (!strcmp(srom_ccode, ccode)) { ++ *mapped_regrev = srom_regrev; ++ mapped = 0; ++ wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__); ++ } else { ++ mapped = ++ brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode, ++ mapped_regrev); ++ } ++ ++ /* find the matching built-in country definition */ ++ country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); ++ ++ /* if there is not an exact rev match, default to rev zero */ ++ if (country == NULL && *mapped_regrev != 0) { ++ *mapped_regrev = 0; ++ country = ++ brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); ++ } ++ ++ return country; ++} ++ ++/* Lookup a country info structure from a null terminated country code ++ * The lookup is case sensitive. ++ */ ++static const struct country_info * ++brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode) ++{ ++ const struct country_info *country; ++ char mapped_ccode[BRCM_CNTRY_BUF_SZ]; ++ uint mapped_regrev; ++ ++ /* ++ * map the country code to a built-in country code, regrev, and ++ * country_info struct ++ */ ++ country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode, ++ &mapped_regrev); ++ ++ return country; ++} ++ ++/* ++ * reset the quiet channels vector to the union ++ * of the restricted and radar channel sets ++ */ ++static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ uint i, j; ++ struct brcms_band *band; ++ const struct brcms_chanvec *chanvec; ++ ++ memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec)); ++ ++ band = wlc->band; ++ for (i = 0; i < wlc->pub->_nbands; ++ i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { ++ ++ /* initialize quiet channels for restricted channels */ ++ chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels; ++ for (j = 0; j < sizeof(struct brcms_chanvec); j++) ++ wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j]; ++ ++ } ++} ++ ++/* Is the channel valid for the current locale and current band? */ ++static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ ++ return ((val < MAXCHANNEL) && ++ isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec, ++ val)); ++} ++ ++/* Is the channel valid for the current locale and specified band? */ ++static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm, ++ uint bandunit, uint val) ++{ ++ return ((val < MAXCHANNEL) ++ && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val)); ++} ++ ++/* Is the channel valid for the current locale? (but don't consider channels not ++ * available due to bandlocking) ++ */ ++static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ ++ return brcms_c_valid_channel20(wlc->cmi, val) || ++ (!wlc->bandlocked ++ && brcms_c_valid_channel20_in_band(wlc->cmi, ++ OTHERBANDUNIT(wlc), val)); ++} ++ ++/* JP, J1 - J10 are Japan ccodes */ ++static bool brcms_c_japan_ccode(const char *ccode) ++{ ++ return (ccode[0] == 'J' && ++ (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9'))); ++} ++ ++/* Returns true if currently set country is Japan or variant */ ++static bool brcms_c_japan(struct brcms_c_info *wlc) ++{ ++ return brcms_c_japan_ccode(wlc->cmi->country_abbrev); ++} ++ ++static void ++brcms_c_channel_min_txpower_limits_with_local_constraint( ++ struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr, ++ u8 local_constraint_qdbm) ++{ ++ int j; ++ ++ /* CCK Rates */ ++ for (j = 0; j < WL_TX_POWER_CCK_NUM; j++) ++ txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm); ++ ++ /* 20 MHz Legacy OFDM SISO */ ++ for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++) ++ txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm); ++ ++ /* 20 MHz Legacy OFDM CDD */ ++ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) ++ txpwr->ofdm_cdd[j] = ++ min(txpwr->ofdm_cdd[j], local_constraint_qdbm); ++ ++ /* 40 MHz Legacy OFDM SISO */ ++ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) ++ txpwr->ofdm_40_siso[j] = ++ min(txpwr->ofdm_40_siso[j], local_constraint_qdbm); ++ ++ /* 40 MHz Legacy OFDM CDD */ ++ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) ++ txpwr->ofdm_40_cdd[j] = ++ min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm); ++ ++ /* 20MHz MCS 0-7 SISO */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_20_siso[j] = ++ min(txpwr->mcs_20_siso[j], local_constraint_qdbm); ++ ++ /* 20MHz MCS 0-7 CDD */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_20_cdd[j] = ++ min(txpwr->mcs_20_cdd[j], local_constraint_qdbm); ++ ++ /* 20MHz MCS 0-7 STBC */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_20_stbc[j] = ++ min(txpwr->mcs_20_stbc[j], local_constraint_qdbm); ++ ++ /* 20MHz MCS 8-15 MIMO */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++) ++ txpwr->mcs_20_mimo[j] = ++ min(txpwr->mcs_20_mimo[j], local_constraint_qdbm); ++ ++ /* 40MHz MCS 0-7 SISO */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_40_siso[j] = ++ min(txpwr->mcs_40_siso[j], local_constraint_qdbm); ++ ++ /* 40MHz MCS 0-7 CDD */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_40_cdd[j] = ++ min(txpwr->mcs_40_cdd[j], local_constraint_qdbm); ++ ++ /* 40MHz MCS 0-7 STBC */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) ++ txpwr->mcs_40_stbc[j] = ++ min(txpwr->mcs_40_stbc[j], local_constraint_qdbm); ++ ++ /* 40MHz MCS 8-15 MIMO */ ++ for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++) ++ txpwr->mcs_40_mimo[j] = ++ min(txpwr->mcs_40_mimo[j], local_constraint_qdbm); ++ ++ /* 40MHz MCS 32 */ ++ txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm); ++ ++} ++ ++/* Update the radio state (enable/disable) and tx power targets ++ * based on a new set of channel/regulatory information ++ */ ++static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ uint chan; ++ struct txpwr_limits txpwr; ++ ++ /* search for the existence of any valid channel */ ++ for (chan = 0; chan < MAXCHANNEL; chan++) { ++ if (brcms_c_valid_channel20_db(wlc->cmi, chan)) ++ break; ++ } ++ if (chan == MAXCHANNEL) ++ chan = INVCHANNEL; ++ ++ /* ++ * based on the channel search above, set or ++ * clear WL_RADIO_COUNTRY_DISABLE. ++ */ ++ if (chan == INVCHANNEL) { ++ /* ++ * country/locale with no valid channels, set ++ * the radio disable bit ++ */ ++ mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); ++ wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" " ++ "nbands %d bandlocked %d\n", wlc->pub->unit, ++ __func__, wlc_cm->country_abbrev, wlc->pub->_nbands, ++ wlc->bandlocked); ++ } else if (mboolisset(wlc->pub->radio_disabled, ++ WL_RADIO_COUNTRY_DISABLE)) { ++ /* ++ * country/locale with valid channel, clear ++ * the radio disable bit ++ */ ++ mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); ++ } ++ ++ /* ++ * Now that the country abbreviation is set, if the radio supports 2G, ++ * then set channel 14 restrictions based on the new locale. ++ */ ++ if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G) ++ wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi, ++ brcms_c_japan(wlc) ? true : ++ false); ++ ++ if (wlc->pub->up && chan != INVCHANNEL) { ++ brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr); ++ brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm, ++ &txpwr, BRCMS_TXPWR_MAX); ++ wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec); ++ } ++} ++ ++static int ++brcms_c_channels_init(struct brcms_cm_info *wlc_cm, ++ const struct country_info *country) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ uint i, j; ++ struct brcms_band *band; ++ const struct locale_info *li; ++ struct brcms_chanvec sup_chan; ++ const struct locale_mimo_info *li_mimo; ++ ++ band = wlc->band; ++ for (i = 0; i < wlc->pub->_nbands; ++ i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { ++ ++ li = (band->bandtype == BRCM_BAND_5G) ? ++ brcms_c_get_locale_5g(country->locale_5G) : ++ brcms_c_get_locale_2g(country->locale_2G); ++ wlc_cm->bandstate[band->bandunit].locale_flags = li->flags; ++ li_mimo = (band->bandtype == BRCM_BAND_5G) ? ++ brcms_c_get_mimo_5g(country->locale_mimo_5G) : ++ brcms_c_get_mimo_2g(country->locale_mimo_2G); ++ ++ /* merge the mimo non-mimo locale flags */ ++ wlc_cm->bandstate[band->bandunit].locale_flags |= ++ li_mimo->flags; ++ ++ wlc_cm->bandstate[band->bandunit].restricted_channels = ++ g_table_restricted_chan[li->restricted_channels]; ++ wlc_cm->bandstate[band->bandunit].radar_channels = ++ g_table_radar_set[li->radar_channels]; ++ ++ /* ++ * set the channel availability, masking out the channels ++ * that may not be supported on this phy. ++ */ ++ wlc_phy_chanspec_band_validch(band->pi, band->bandtype, ++ &sup_chan); ++ brcms_c_locale_get_channels(li, ++ &wlc_cm->bandstate[band->bandunit]. ++ valid_channels); ++ for (j = 0; j < sizeof(struct brcms_chanvec); j++) ++ wlc_cm->bandstate[band->bandunit].valid_channels. ++ vec[j] &= sup_chan.vec[j]; ++ } ++ ++ brcms_c_quiet_channels_reset(wlc_cm); ++ brcms_c_channels_commit(wlc_cm); ++ ++ return 0; ++} ++ ++/* ++ * set the driver's current country and regulatory information ++ * using a country code as the source. Look up built in country ++ * information found with the country code. ++ */ ++static void ++brcms_c_set_country_common(struct brcms_cm_info *wlc_cm, ++ const char *country_abbrev, ++ const char *ccode, uint regrev, ++ const struct country_info *country) ++{ ++ const struct locale_info *locale; ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ char prev_country_abbrev[BRCM_CNTRY_BUF_SZ]; ++ ++ /* save current country state */ ++ wlc_cm->country = country; ++ ++ memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ); ++ strncpy(prev_country_abbrev, wlc_cm->country_abbrev, ++ BRCM_CNTRY_BUF_SZ - 1); ++ ++ strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); ++ strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); ++ wlc_cm->regrev = regrev; ++ ++ if ((wlc->pub->_n_enab & SUPPORT_11N) != ++ wlc->protection->nmode_user) ++ brcms_c_set_nmode(wlc); ++ ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); ++ /* set or restore gmode as required by regulatory */ ++ locale = brcms_c_get_locale_2g(country->locale_2G); ++ if (locale && (locale->flags & BRCMS_NO_OFDM)) ++ brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false); ++ else ++ brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); ++ ++ brcms_c_channels_init(wlc_cm, country); ++ ++ return; ++} ++ ++static int ++brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm, ++ const char *country_abbrev, ++ const char *ccode, int regrev) ++{ ++ const struct country_info *country; ++ char mapped_ccode[BRCM_CNTRY_BUF_SZ]; ++ uint mapped_regrev; ++ ++ /* if regrev is -1, lookup the mapped country code, ++ * otherwise use the ccode and regrev directly ++ */ ++ if (regrev == -1) { ++ /* ++ * map the country code to a built-in country ++ * code, regrev, and country_info ++ */ ++ country = ++ brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode, ++ &mapped_regrev); ++ } else { ++ /* find the matching built-in country definition */ ++ country = brcms_c_country_lookup_direct(ccode, regrev); ++ strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); ++ mapped_regrev = regrev; ++ } ++ ++ if (country == NULL) ++ return -EINVAL; ++ ++ /* set the driver state for the country */ ++ brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode, ++ mapped_regrev, country); ++ ++ return 0; ++} ++ ++/* ++ * set the driver's current country and regulatory information using ++ * a country code as the source. Lookup built in country information ++ * found with the country code. ++ */ ++static int ++brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode) ++{ ++ char country_abbrev[BRCM_CNTRY_BUF_SZ]; ++ strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ); ++ return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1); ++} ++ ++struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) ++{ ++ struct brcms_cm_info *wlc_cm; ++ char country_abbrev[BRCM_CNTRY_BUF_SZ]; ++ const struct country_info *country; ++ struct brcms_pub *pub = wlc->pub; ++ char *ccode; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC); ++ if (wlc_cm == NULL) ++ return NULL; ++ wlc_cm->pub = pub; ++ wlc_cm->wlc = wlc; ++ wlc->cmi = wlc_cm; ++ ++ /* store the country code for passing up as a regulatory hint */ ++ ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE); ++ if (ccode) ++ strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); ++ ++ /* ++ * internal country information which must match ++ * regulatory constraints in firmware ++ */ ++ memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ); ++ strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1); ++ country = brcms_c_country_lookup(wlc, country_abbrev); ++ ++ /* save default country for exiting 11d regulatory mode */ ++ strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); ++ ++ /* initialize autocountry_default to driver default */ ++ strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1); ++ ++ brcms_c_set_countrycode(wlc_cm, country_abbrev); ++ ++ return wlc_cm; ++} ++ ++void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm) ++{ ++ kfree(wlc_cm); ++} ++ ++u8 ++brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, ++ uint bandunit) ++{ ++ return wlc_cm->bandstate[bandunit].locale_flags; ++} ++ ++static bool ++brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec) ++{ ++ return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) && ++ CHSPEC_IS40(chspec) ? ++ (isset(wlc_cm->quiet_channels.vec, ++ lower_20_sb(CHSPEC_CHANNEL(chspec))) || ++ isset(wlc_cm->quiet_channels.vec, ++ upper_20_sb(CHSPEC_CHANNEL(chspec)))) : ++ isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec)); ++} ++ ++void ++brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, ++ u8 local_constraint_qdbm) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ struct txpwr_limits txpwr; ++ ++ brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr); ++ ++ brcms_c_channel_min_txpower_limits_with_local_constraint( ++ wlc_cm, &txpwr, local_constraint_qdbm ++ ); ++ ++ brcms_b_set_chanspec(wlc->hw, chanspec, ++ (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0), ++ &txpwr); ++} ++ ++#ifdef POWER_DBG ++static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr) ++{ ++ int i; ++ char buf[80]; ++ char fraction[4][4] = { " ", ".25", ".5 ", ".75" }; ++ ++ sprintf(buf, "CCK "); ++ for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz OFDM SISO "); ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz OFDM CDD "); ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz OFDM SISO "); ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->ofdm_40_siso[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz OFDM CDD "); ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->ofdm_40_cdd[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz MCS0-7 SISO "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_20_siso[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz MCS0-7 CDD "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_20_cdd[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz MCS0-7 STBC "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_20_stbc[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "20 MHz MCS8-15 SDM "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_20_mimo[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz MCS0-7 SISO "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_40_siso[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz MCS0-7 CDD "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_40_cdd[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz MCS0-7 STBC "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_40_stbc[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ sprintf(buf, "40 MHz MCS8-15 SDM "); ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) ++ sprintf(buf[strlen(buf)], " %2d%s", ++ txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs_40_mimo[i] % ++ BRCMS_TXPWR_DB_FACTOR]); ++ } ++ printk(KERN_DEBUG "%s\n", buf); ++ ++ printk(KERN_DEBUG "MCS32 %2d%s\n", ++ txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR, ++ fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]); ++} ++#endif /* POWER_DBG */ ++ ++void ++brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, ++ struct txpwr_limits *txpwr) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ uint i; ++ uint chan; ++ int maxpwr; ++ int delta; ++ const struct country_info *country; ++ struct brcms_band *band; ++ const struct locale_info *li; ++ int conducted_max = BRCMS_TXPWR_MAX; ++ int conducted_ofdm_max = BRCMS_TXPWR_MAX; ++ const struct locale_mimo_info *li_mimo; ++ int maxpwr20, maxpwr40; ++ int maxpwr_idx; ++ uint j; ++ ++ memset(txpwr, 0, sizeof(struct txpwr_limits)); ++ ++ if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) { ++ country = brcms_c_country_lookup(wlc, wlc->autocountry_default); ++ if (country == NULL) ++ return; ++ } else { ++ country = wlc_cm->country; ++ } ++ ++ chan = CHSPEC_CHANNEL(chanspec); ++ band = wlc->bandstate[chspec_bandunit(chanspec)]; ++ li = (band->bandtype == BRCM_BAND_5G) ? ++ brcms_c_get_locale_5g(country->locale_5G) : ++ brcms_c_get_locale_2g(country->locale_2G); ++ ++ li_mimo = (band->bandtype == BRCM_BAND_5G) ? ++ brcms_c_get_mimo_5g(country->locale_mimo_5G) : ++ brcms_c_get_mimo_2g(country->locale_mimo_2G); ++ ++ if (li->flags & BRCMS_EIRP) { ++ delta = band->antgain; ++ } else { ++ delta = 0; ++ if (band->antgain > QDB(6)) ++ delta = band->antgain - QDB(6); /* Excess over 6 dB */ ++ } ++ ++ if (li == &locale_i) { ++ conducted_max = QDB(22); ++ conducted_ofdm_max = QDB(22); ++ } ++ ++ /* CCK txpwr limits for 2.4G band */ ++ if (band->bandtype == BRCM_BAND_2G) { ++ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)]; ++ ++ maxpwr = maxpwr - delta; ++ maxpwr = max(maxpwr, 0); ++ maxpwr = min(maxpwr, conducted_max); ++ ++ for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) ++ txpwr->cck[i] = (u8) maxpwr; ++ } ++ ++ /* OFDM txpwr limits for 2.4G or 5G bands */ ++ if (band->bandtype == BRCM_BAND_2G) ++ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)]; ++ else ++ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)]; ++ ++ maxpwr = maxpwr - delta; ++ maxpwr = max(maxpwr, 0); ++ maxpwr = min(maxpwr, conducted_ofdm_max); ++ ++ /* Keep OFDM lmit below CCK limit */ ++ if (band->bandtype == BRCM_BAND_2G) ++ maxpwr = min_t(int, maxpwr, txpwr->cck[0]); ++ ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) ++ txpwr->ofdm[i] = (u8) maxpwr; ++ ++ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) { ++ /* ++ * OFDM 40 MHz SISO has the same power as the corresponding ++ * MCS0-7 rate unless overriden by the locale specific code. ++ * We set this value to 0 as a flag (presumably 0 dBm isn't ++ * a possibility) and then copy the MCS0-7 value to the 40 MHz ++ * value if it wasn't explicitly set. ++ */ ++ txpwr->ofdm_40_siso[i] = 0; ++ ++ txpwr->ofdm_cdd[i] = (u8) maxpwr; ++ ++ txpwr->ofdm_40_cdd[i] = 0; ++ } ++ ++ /* MIMO/HT specific limits */ ++ if (li_mimo->flags & BRCMS_EIRP) { ++ delta = band->antgain; ++ } else { ++ delta = 0; ++ if (band->antgain > QDB(6)) ++ delta = band->antgain - QDB(6); /* Excess over 6 dB */ ++ } ++ ++ if (band->bandtype == BRCM_BAND_2G) ++ maxpwr_idx = (chan - 1); ++ else ++ maxpwr_idx = CHANNEL_POWER_IDX_5G(chan); ++ ++ maxpwr20 = li_mimo->maxpwr20[maxpwr_idx]; ++ maxpwr40 = li_mimo->maxpwr40[maxpwr_idx]; ++ ++ maxpwr20 = maxpwr20 - delta; ++ maxpwr20 = max(maxpwr20, 0); ++ maxpwr40 = maxpwr40 - delta; ++ maxpwr40 = max(maxpwr40, 0); ++ ++ /* Fill in the MCS 0-7 (SISO) rates */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ ++ /* ++ * 20 MHz has the same power as the corresponding OFDM rate ++ * unless overriden by the locale specific code. ++ */ ++ txpwr->mcs_20_siso[i] = txpwr->ofdm[i]; ++ txpwr->mcs_40_siso[i] = 0; ++ } ++ ++ /* Fill in the MCS 0-7 CDD rates */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ txpwr->mcs_20_cdd[i] = (u8) maxpwr20; ++ txpwr->mcs_40_cdd[i] = (u8) maxpwr40; ++ } ++ ++ /* ++ * These locales have SISO expressed in the ++ * table and override CDD later ++ */ ++ if (li_mimo == &locale_bn) { ++ if (li_mimo == &locale_bn) { ++ maxpwr20 = QDB(16); ++ maxpwr40 = 0; ++ ++ if (chan >= 3 && chan <= 11) ++ maxpwr40 = QDB(16); ++ } ++ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ txpwr->mcs_20_siso[i] = (u8) maxpwr20; ++ txpwr->mcs_40_siso[i] = (u8) maxpwr40; ++ } ++ } ++ ++ /* Fill in the MCS 0-7 STBC rates */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ txpwr->mcs_20_stbc[i] = 0; ++ txpwr->mcs_40_stbc[i] = 0; ++ } ++ ++ /* Fill in the MCS 8-15 SDM rates */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) { ++ txpwr->mcs_20_mimo[i] = (u8) maxpwr20; ++ txpwr->mcs_40_mimo[i] = (u8) maxpwr40; ++ } ++ ++ /* Fill in MCS32 */ ++ txpwr->mcs32 = (u8) maxpwr40; ++ ++ for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) { ++ if (txpwr->ofdm_40_cdd[i] == 0) ++ txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j]; ++ if (i == 0) { ++ i = i + 1; ++ if (txpwr->ofdm_40_cdd[i] == 0) ++ txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j]; ++ } ++ } ++ ++ /* ++ * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO ++ * value if it wasn't provided explicitly. ++ */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ if (txpwr->mcs_40_siso[i] == 0) ++ txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i]; ++ } ++ ++ for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) { ++ if (txpwr->ofdm_40_siso[i] == 0) ++ txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j]; ++ if (i == 0) { ++ i = i + 1; ++ if (txpwr->ofdm_40_siso[i] == 0) ++ txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j]; ++ } ++ } ++ ++ /* ++ * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding ++ * STBC values if they weren't provided explicitly. ++ */ ++ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { ++ if (txpwr->mcs_20_stbc[i] == 0) ++ txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i]; ++ ++ if (txpwr->mcs_40_stbc[i] == 0) ++ txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i]; ++ } ++ ++#ifdef POWER_DBG ++ wlc_phy_txpower_limits_dump(txpwr); ++#endif ++ return; ++} ++ ++/* ++ * Verify the chanspec is using a legal set of parameters, i.e. that the ++ * chanspec specified a band, bw, ctl_sb and channel and that the ++ * combination could be legal given any set of circumstances. ++ * RETURNS: true is the chanspec is malformed, false if it looks good. ++ */ ++static bool brcms_c_chspec_malformed(u16 chanspec) ++{ ++ /* must be 2G or 5G band */ ++ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) ++ return true; ++ /* must be 20 or 40 bandwidth */ ++ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) ++ return true; ++ ++ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ ++ if (CHSPEC_IS20(chanspec)) { ++ if (!CHSPEC_SB_NONE(chanspec)) ++ return true; ++ } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * Validate the chanspec for this locale, for 40MHZ we need to also ++ * check that the sidebands are valid 20MZH channels in this locale ++ * and they are also a legal HT combination ++ */ ++static bool ++brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec, ++ bool dualband) ++{ ++ struct brcms_c_info *wlc = wlc_cm->wlc; ++ u8 channel = CHSPEC_CHANNEL(chspec); ++ ++ /* check the chanspec */ ++ if (brcms_c_chspec_malformed(chspec)) { ++ wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n", ++ wlc->pub->unit, chspec); ++ return false; ++ } ++ ++ if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) != ++ chspec_bandunit(chspec)) ++ return false; ++ ++ /* Check a 20Mhz channel */ ++ if (CHSPEC_IS20(chspec)) { ++ if (dualband) ++ return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi, ++ channel); ++ else ++ return brcms_c_valid_channel20(wlc_cm->wlc->cmi, ++ channel); ++ } ++#ifdef SUPPORT_40MHZ ++ /* ++ * We know we are now checking a 40MHZ channel, so we should ++ * only be here for NPHYS ++ */ ++ if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) { ++ u8 upper_sideband = 0, idx; ++ u8 num_ch20_entries = ++ sizeof(chan20_info) / sizeof(struct chan20_info); ++ ++ if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec))) ++ return false; ++ ++ if (dualband) { ++ if (!brcms_c_valid_channel20_db(wlc->cmi, ++ lower_20_sb(channel)) || ++ !brcms_c_valid_channel20_db(wlc->cmi, ++ upper_20_sb(channel))) ++ return false; ++ } else { ++ if (!brcms_c_valid_channel20(wlc->cmi, ++ lower_20_sb(channel)) || ++ !brcms_c_valid_channel20(wlc->cmi, ++ upper_20_sb(channel))) ++ return false; ++ } ++ ++ /* find the lower sideband info in the sideband array */ ++ for (idx = 0; idx < num_ch20_entries; idx++) { ++ if (chan20_info[idx].sb == lower_20_sb(channel)) ++ upper_sideband = chan20_info[idx].adj_sbs; ++ } ++ /* check that the lower sideband allows an upper sideband */ ++ if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) == ++ (CH_UPPER_SB | CH_EWA_VALID)) ++ return true; ++ return false; ++ } ++#endif /* 40 MHZ */ ++ ++ return false; ++} ++ ++bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec) ++{ ++ return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.h.orig 2011-11-09 13:46:58.242800670 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/channel.h 2011-11-09 13:47:16.994566241 -0500 +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_CHANNEL_H_ ++#define _BRCM_CHANNEL_H_ ++ ++/* conversion for phy txpwr calculations that use .25 dB units */ ++#define BRCMS_TXPWR_DB_FACTOR 4 ++ ++/* bits for locale_info flags */ ++#define BRCMS_PEAK_CONDUCTED 0x00 /* Peak for locals */ ++#define BRCMS_EIRP 0x01 /* Flag for EIRP */ ++#define BRCMS_DFS_TPC 0x02 /* Flag for DFS TPC */ ++#define BRCMS_NO_OFDM 0x04 /* Flag for No OFDM */ ++#define BRCMS_NO_40MHZ 0x08 /* Flag for No MIMO 40MHz */ ++#define BRCMS_NO_MIMO 0x10 /* Flag for No MIMO, 20 or 40 MHz */ ++#define BRCMS_RADAR_TYPE_EU 0x20 /* Flag for EU */ ++#define BRCMS_DFS_FCC BRCMS_DFS_TPC /* Flag for DFS FCC */ ++ ++#define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */ ++ ++extern struct brcms_cm_info * ++brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); ++ ++extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); ++ ++extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, ++ uint bandunit); ++ ++extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, ++ u16 chspec); ++ ++extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, ++ u16 chanspec, ++ struct txpwr_limits *txpwr); ++extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, ++ u16 chanspec, ++ u8 local_constraint_qdbm); ++ ++#endif /* _WLC_CHANNEL_H */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/d11.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/d11.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/d11.h.orig 2011-11-09 13:46:58.243800657 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/d11.h 2011-11-09 13:47:16.996566217 -0500 +@@ -0,0 +1,1898 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_D11_H_ ++#define _BRCM_D11_H_ ++ ++#include ++ ++#include ++#include "pub.h" ++#include "dma.h" ++ ++/* RX FIFO numbers */ ++#define RX_FIFO 0 /* data and ctl frames */ ++#define RX_TXSTATUS_FIFO 3 /* RX fifo for tx status packages */ ++ ++/* TX FIFO numbers using WME Access Category */ ++#define TX_AC_BK_FIFO 0 /* Background TX FIFO */ ++#define TX_AC_BE_FIFO 1 /* Best-Effort TX FIFO */ ++#define TX_AC_VI_FIFO 2 /* Video TX FIFO */ ++#define TX_AC_VO_FIFO 3 /* Voice TX FIFO */ ++#define TX_BCMC_FIFO 4 /* Broadcast/Multicast TX FIFO */ ++#define TX_ATIM_FIFO 5 /* TX fifo for ATIM window info */ ++ ++/* Addr is byte address used by SW; offset is word offset used by uCode */ ++ ++/* Per AC TX limit settings */ ++#define M_AC_TXLMT_BASE_ADDR (0x180 * 2) ++#define M_AC_TXLMT_ADDR(_ac) (M_AC_TXLMT_BASE_ADDR + (2 * (_ac))) ++ ++/* Legacy TX FIFO numbers */ ++#define TX_DATA_FIFO TX_AC_BE_FIFO ++#define TX_CTL_FIFO TX_AC_VO_FIFO ++ ++#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ ++ ++struct intctrlregs { ++ u32 intstatus; ++ u32 intmask; ++}; ++ ++/* PIO structure, ++ * support two PIO format: 2 bytes access and 4 bytes access ++ * basic FIFO register set is per channel(transmit or receive) ++ * a pair of channels is defined for convenience ++ */ ++/* 2byte-wide pio register set per channel(xmt or rcv) */ ++struct pio2regs { ++ u16 fifocontrol; ++ u16 fifodata; ++ u16 fifofree; /* only valid in xmt channel, not in rcv channel */ ++ u16 PAD; ++}; ++ ++/* a pair of pio channels(tx and rx) */ ++struct pio2regp { ++ struct pio2regs tx; ++ struct pio2regs rx; ++}; ++ ++/* 4byte-wide pio register set per channel(xmt or rcv) */ ++struct pio4regs { ++ u32 fifocontrol; ++ u32 fifodata; ++}; ++ ++/* a pair of pio channels(tx and rx) */ ++struct pio4regp { ++ struct pio4regs tx; ++ struct pio4regs rx; ++}; ++ ++/* read: 32-bit register that can be read as 32-bit or as 2 16-bit ++ * write: only low 16b-it half can be written ++ */ ++union pmqreg { ++ u32 pmqhostdata; /* read only! */ ++ struct { ++ u16 pmqctrlstatus; /* read/write */ ++ u16 PAD; ++ } w; ++}; ++ ++struct fifo64 { ++ struct dma64regs dmaxmt; /* dma tx */ ++ struct pio4regs piotx; /* pio tx */ ++ struct dma64regs dmarcv; /* dma rx */ ++ struct pio4regs piorx; /* pio rx */ ++}; ++ ++/* ++ * Host Interface Registers ++ */ ++struct d11regs { ++ /* Device Control ("semi-standard host registers") */ ++ u32 PAD[3]; /* 0x0 - 0x8 */ ++ u32 biststatus; /* 0xC */ ++ u32 biststatus2; /* 0x10 */ ++ u32 PAD; /* 0x14 */ ++ u32 gptimer; /* 0x18 */ ++ u32 usectimer; /* 0x1c *//* for corerev >= 26 */ ++ ++ /* Interrupt Control *//* 0x20 */ ++ struct intctrlregs intctrlregs[8]; ++ ++ u32 PAD[40]; /* 0x60 - 0xFC */ ++ ++ u32 intrcvlazy[4]; /* 0x100 - 0x10C */ ++ ++ u32 PAD[4]; /* 0x110 - 0x11c */ ++ ++ u32 maccontrol; /* 0x120 */ ++ u32 maccommand; /* 0x124 */ ++ u32 macintstatus; /* 0x128 */ ++ u32 macintmask; /* 0x12C */ ++ ++ /* Transmit Template Access */ ++ u32 tplatewrptr; /* 0x130 */ ++ u32 tplatewrdata; /* 0x134 */ ++ u32 PAD[2]; /* 0x138 - 0x13C */ ++ ++ /* PMQ registers */ ++ union pmqreg pmqreg; /* 0x140 */ ++ u32 pmqpatl; /* 0x144 */ ++ u32 pmqpath; /* 0x148 */ ++ u32 PAD; /* 0x14C */ ++ ++ u32 chnstatus; /* 0x150 */ ++ u32 psmdebug; /* 0x154 */ ++ u32 phydebug; /* 0x158 */ ++ u32 machwcap; /* 0x15C */ ++ ++ /* Extended Internal Objects */ ++ u32 objaddr; /* 0x160 */ ++ u32 objdata; /* 0x164 */ ++ u32 PAD[2]; /* 0x168 - 0x16c */ ++ ++ u32 frmtxstatus; /* 0x170 */ ++ u32 frmtxstatus2; /* 0x174 */ ++ u32 PAD[2]; /* 0x178 - 0x17c */ ++ ++ /* TSF host access */ ++ u32 tsf_timerlow; /* 0x180 */ ++ u32 tsf_timerhigh; /* 0x184 */ ++ u32 tsf_cfprep; /* 0x188 */ ++ u32 tsf_cfpstart; /* 0x18c */ ++ u32 tsf_cfpmaxdur32; /* 0x190 */ ++ u32 PAD[3]; /* 0x194 - 0x19c */ ++ ++ u32 maccontrol1; /* 0x1a0 */ ++ u32 machwcap1; /* 0x1a4 */ ++ u32 PAD[14]; /* 0x1a8 - 0x1dc */ ++ ++ /* Clock control and hardware workarounds*/ ++ u32 clk_ctl_st; /* 0x1e0 */ ++ u32 hw_war; ++ u32 d11_phypllctl; /* the phypll request/avail bits are ++ * moved to clk_ctl_st ++ */ ++ u32 PAD[5]; /* 0x1ec - 0x1fc */ ++ ++ /* 0x200-0x37F dma/pio registers */ ++ struct fifo64 fifo64regs[6]; ++ ++ /* FIFO diagnostic port access */ ++ struct dma32diag dmafifo; /* 0x380 - 0x38C */ ++ ++ u32 aggfifocnt; /* 0x390 */ ++ u32 aggfifodata; /* 0x394 */ ++ u32 PAD[16]; /* 0x398 - 0x3d4 */ ++ u16 radioregaddr; /* 0x3d8 */ ++ u16 radioregdata; /* 0x3da */ ++ ++ /* ++ * time delay between the change on rf disable input and ++ * radio shutdown ++ */ ++ u32 rfdisabledly; /* 0x3DC */ ++ ++ /* PHY register access */ ++ u16 phyversion; /* 0x3e0 - 0x0 */ ++ u16 phybbconfig; /* 0x3e2 - 0x1 */ ++ u16 phyadcbias; /* 0x3e4 - 0x2 Bphy only */ ++ u16 phyanacore; /* 0x3e6 - 0x3 pwwrdwn on aphy */ ++ u16 phyrxstatus0; /* 0x3e8 - 0x4 */ ++ u16 phyrxstatus1; /* 0x3ea - 0x5 */ ++ u16 phycrsth; /* 0x3ec - 0x6 */ ++ u16 phytxerror; /* 0x3ee - 0x7 */ ++ u16 phychannel; /* 0x3f0 - 0x8 */ ++ u16 PAD[1]; /* 0x3f2 - 0x9 */ ++ u16 phytest; /* 0x3f4 - 0xa */ ++ u16 phy4waddr; /* 0x3f6 - 0xb */ ++ u16 phy4wdatahi; /* 0x3f8 - 0xc */ ++ u16 phy4wdatalo; /* 0x3fa - 0xd */ ++ u16 phyregaddr; /* 0x3fc - 0xe */ ++ u16 phyregdata; /* 0x3fe - 0xf */ ++ ++ /* IHR *//* 0x400 - 0x7FE */ ++ ++ /* RXE Block */ ++ u16 PAD[3]; /* 0x400 - 0x406 */ ++ u16 rcv_fifo_ctl; /* 0x406 */ ++ u16 PAD; /* 0x408 - 0x40a */ ++ u16 rcv_frm_cnt; /* 0x40a */ ++ u16 PAD[4]; /* 0x40a - 0x414 */ ++ u16 rssi; /* 0x414 */ ++ u16 PAD[5]; /* 0x414 - 0x420 */ ++ u16 rcm_ctl; /* 0x420 */ ++ u16 rcm_mat_data; /* 0x422 */ ++ u16 rcm_mat_mask; /* 0x424 */ ++ u16 rcm_mat_dly; /* 0x426 */ ++ u16 rcm_cond_mask_l; /* 0x428 */ ++ u16 rcm_cond_mask_h; /* 0x42A */ ++ u16 rcm_cond_dly; /* 0x42C */ ++ u16 PAD[1]; /* 0x42E */ ++ u16 ext_ihr_addr; /* 0x430 */ ++ u16 ext_ihr_data; /* 0x432 */ ++ u16 rxe_phyrs_2; /* 0x434 */ ++ u16 rxe_phyrs_3; /* 0x436 */ ++ u16 phy_mode; /* 0x438 */ ++ u16 rcmta_ctl; /* 0x43a */ ++ u16 rcmta_size; /* 0x43c */ ++ u16 rcmta_addr0; /* 0x43e */ ++ u16 rcmta_addr1; /* 0x440 */ ++ u16 rcmta_addr2; /* 0x442 */ ++ u16 PAD[30]; /* 0x444 - 0x480 */ ++ ++ /* PSM Block *//* 0x480 - 0x500 */ ++ ++ u16 PAD; /* 0x480 */ ++ u16 psm_maccontrol_h; /* 0x482 */ ++ u16 psm_macintstatus_l; /* 0x484 */ ++ u16 psm_macintstatus_h; /* 0x486 */ ++ u16 psm_macintmask_l; /* 0x488 */ ++ u16 psm_macintmask_h; /* 0x48A */ ++ u16 PAD; /* 0x48C */ ++ u16 psm_maccommand; /* 0x48E */ ++ u16 psm_brc; /* 0x490 */ ++ u16 psm_phy_hdr_param; /* 0x492 */ ++ u16 psm_postcard; /* 0x494 */ ++ u16 psm_pcard_loc_l; /* 0x496 */ ++ u16 psm_pcard_loc_h; /* 0x498 */ ++ u16 psm_gpio_in; /* 0x49A */ ++ u16 psm_gpio_out; /* 0x49C */ ++ u16 psm_gpio_oe; /* 0x49E */ ++ ++ u16 psm_bred_0; /* 0x4A0 */ ++ u16 psm_bred_1; /* 0x4A2 */ ++ u16 psm_bred_2; /* 0x4A4 */ ++ u16 psm_bred_3; /* 0x4A6 */ ++ u16 psm_brcl_0; /* 0x4A8 */ ++ u16 psm_brcl_1; /* 0x4AA */ ++ u16 psm_brcl_2; /* 0x4AC */ ++ u16 psm_brcl_3; /* 0x4AE */ ++ u16 psm_brpo_0; /* 0x4B0 */ ++ u16 psm_brpo_1; /* 0x4B2 */ ++ u16 psm_brpo_2; /* 0x4B4 */ ++ u16 psm_brpo_3; /* 0x4B6 */ ++ u16 psm_brwk_0; /* 0x4B8 */ ++ u16 psm_brwk_1; /* 0x4BA */ ++ u16 psm_brwk_2; /* 0x4BC */ ++ u16 psm_brwk_3; /* 0x4BE */ ++ ++ u16 psm_base_0; /* 0x4C0 */ ++ u16 psm_base_1; /* 0x4C2 */ ++ u16 psm_base_2; /* 0x4C4 */ ++ u16 psm_base_3; /* 0x4C6 */ ++ u16 psm_base_4; /* 0x4C8 */ ++ u16 psm_base_5; /* 0x4CA */ ++ u16 psm_base_6; /* 0x4CC */ ++ u16 psm_pc_reg_0; /* 0x4CE */ ++ u16 psm_pc_reg_1; /* 0x4D0 */ ++ u16 psm_pc_reg_2; /* 0x4D2 */ ++ u16 psm_pc_reg_3; /* 0x4D4 */ ++ u16 PAD[0xD]; /* 0x4D6 - 0x4DE */ ++ u16 psm_corectlsts; /* 0x4f0 *//* Corerev >= 13 */ ++ u16 PAD[0x7]; /* 0x4f2 - 0x4fE */ ++ ++ /* TXE0 Block *//* 0x500 - 0x580 */ ++ u16 txe_ctl; /* 0x500 */ ++ u16 txe_aux; /* 0x502 */ ++ u16 txe_ts_loc; /* 0x504 */ ++ u16 txe_time_out; /* 0x506 */ ++ u16 txe_wm_0; /* 0x508 */ ++ u16 txe_wm_1; /* 0x50A */ ++ u16 txe_phyctl; /* 0x50C */ ++ u16 txe_status; /* 0x50E */ ++ u16 txe_mmplcp0; /* 0x510 */ ++ u16 txe_mmplcp1; /* 0x512 */ ++ u16 txe_phyctl1; /* 0x514 */ ++ ++ u16 PAD[0x05]; /* 0x510 - 0x51E */ ++ ++ /* Transmit control */ ++ u16 xmtfifodef; /* 0x520 */ ++ u16 xmtfifo_frame_cnt; /* 0x522 *//* Corerev >= 16 */ ++ u16 xmtfifo_byte_cnt; /* 0x524 *//* Corerev >= 16 */ ++ u16 xmtfifo_head; /* 0x526 *//* Corerev >= 16 */ ++ u16 xmtfifo_rd_ptr; /* 0x528 *//* Corerev >= 16 */ ++ u16 xmtfifo_wr_ptr; /* 0x52A *//* Corerev >= 16 */ ++ u16 xmtfifodef1; /* 0x52C *//* Corerev >= 16 */ ++ ++ u16 PAD[0x09]; /* 0x52E - 0x53E */ ++ ++ u16 xmtfifocmd; /* 0x540 */ ++ u16 xmtfifoflush; /* 0x542 */ ++ u16 xmtfifothresh; /* 0x544 */ ++ u16 xmtfifordy; /* 0x546 */ ++ u16 xmtfifoprirdy; /* 0x548 */ ++ u16 xmtfiforqpri; /* 0x54A */ ++ u16 xmttplatetxptr; /* 0x54C */ ++ u16 PAD; /* 0x54E */ ++ u16 xmttplateptr; /* 0x550 */ ++ u16 smpl_clct_strptr; /* 0x552 *//* Corerev >= 22 */ ++ u16 smpl_clct_stpptr; /* 0x554 *//* Corerev >= 22 */ ++ u16 smpl_clct_curptr; /* 0x556 *//* Corerev >= 22 */ ++ u16 PAD[0x04]; /* 0x558 - 0x55E */ ++ u16 xmttplatedatalo; /* 0x560 */ ++ u16 xmttplatedatahi; /* 0x562 */ ++ ++ u16 PAD[2]; /* 0x564 - 0x566 */ ++ ++ u16 xmtsel; /* 0x568 */ ++ u16 xmttxcnt; /* 0x56A */ ++ u16 xmttxshmaddr; /* 0x56C */ ++ ++ u16 PAD[0x09]; /* 0x56E - 0x57E */ ++ ++ /* TXE1 Block */ ++ u16 PAD[0x40]; /* 0x580 - 0x5FE */ ++ ++ /* TSF Block */ ++ u16 PAD[0X02]; /* 0x600 - 0x602 */ ++ u16 tsf_cfpstrt_l; /* 0x604 */ ++ u16 tsf_cfpstrt_h; /* 0x606 */ ++ u16 PAD[0X05]; /* 0x608 - 0x610 */ ++ u16 tsf_cfppretbtt; /* 0x612 */ ++ u16 PAD[0XD]; /* 0x614 - 0x62C */ ++ u16 tsf_clk_frac_l; /* 0x62E */ ++ u16 tsf_clk_frac_h; /* 0x630 */ ++ u16 PAD[0X14]; /* 0x632 - 0x658 */ ++ u16 tsf_random; /* 0x65A */ ++ u16 PAD[0x05]; /* 0x65C - 0x664 */ ++ /* GPTimer 2 registers */ ++ u16 tsf_gpt2_stat; /* 0x666 */ ++ u16 tsf_gpt2_ctr_l; /* 0x668 */ ++ u16 tsf_gpt2_ctr_h; /* 0x66A */ ++ u16 tsf_gpt2_val_l; /* 0x66C */ ++ u16 tsf_gpt2_val_h; /* 0x66E */ ++ u16 tsf_gptall_stat; /* 0x670 */ ++ u16 PAD[0x07]; /* 0x672 - 0x67E */ ++ ++ /* IFS Block */ ++ u16 ifs_sifs_rx_tx_tx; /* 0x680 */ ++ u16 ifs_sifs_nav_tx; /* 0x682 */ ++ u16 ifs_slot; /* 0x684 */ ++ u16 PAD; /* 0x686 */ ++ u16 ifs_ctl; /* 0x688 */ ++ u16 PAD[0x3]; /* 0x68a - 0x68F */ ++ u16 ifsstat; /* 0x690 */ ++ u16 ifsmedbusyctl; /* 0x692 */ ++ u16 iftxdur; /* 0x694 */ ++ u16 PAD[0x3]; /* 0x696 - 0x69b */ ++ /* EDCF support in dot11macs */ ++ u16 ifs_aifsn; /* 0x69c */ ++ u16 ifs_ctl1; /* 0x69e */ ++ ++ /* slow clock registers */ ++ u16 scc_ctl; /* 0x6a0 */ ++ u16 scc_timer_l; /* 0x6a2 */ ++ u16 scc_timer_h; /* 0x6a4 */ ++ u16 scc_frac; /* 0x6a6 */ ++ u16 scc_fastpwrup_dly; /* 0x6a8 */ ++ u16 scc_per; /* 0x6aa */ ++ u16 scc_per_frac; /* 0x6ac */ ++ u16 scc_cal_timer_l; /* 0x6ae */ ++ u16 scc_cal_timer_h; /* 0x6b0 */ ++ u16 PAD; /* 0x6b2 */ ++ ++ u16 PAD[0x26]; ++ ++ /* NAV Block */ ++ u16 nav_ctl; /* 0x700 */ ++ u16 navstat; /* 0x702 */ ++ u16 PAD[0x3e]; /* 0x702 - 0x77E */ ++ ++ /* WEP/PMQ Block *//* 0x780 - 0x7FE */ ++ u16 PAD[0x20]; /* 0x780 - 0x7BE */ ++ ++ u16 wepctl; /* 0x7C0 */ ++ u16 wepivloc; /* 0x7C2 */ ++ u16 wepivkey; /* 0x7C4 */ ++ u16 wepwkey; /* 0x7C6 */ ++ ++ u16 PAD[4]; /* 0x7C8 - 0x7CE */ ++ u16 pcmctl; /* 0X7D0 */ ++ u16 pcmstat; /* 0X7D2 */ ++ u16 PAD[6]; /* 0x7D4 - 0x7DE */ ++ ++ u16 pmqctl; /* 0x7E0 */ ++ u16 pmqstatus; /* 0x7E2 */ ++ u16 pmqpat0; /* 0x7E4 */ ++ u16 pmqpat1; /* 0x7E6 */ ++ u16 pmqpat2; /* 0x7E8 */ ++ ++ u16 pmqdat; /* 0x7EA */ ++ u16 pmqdator; /* 0x7EC */ ++ u16 pmqhst; /* 0x7EE */ ++ u16 pmqpath0; /* 0x7F0 */ ++ u16 pmqpath1; /* 0x7F2 */ ++ u16 pmqpath2; /* 0x7F4 */ ++ u16 pmqdath; /* 0x7F6 */ ++ ++ u16 PAD[0x04]; /* 0x7F8 - 0x7FE */ ++ ++ /* SHM *//* 0x800 - 0xEFE */ ++ u16 PAD[0x380]; /* 0x800 - 0xEFE */ ++}; ++ ++#define PIHR_BASE 0x0400 /* byte address of packed IHR region */ ++ ++/* biststatus */ ++#define BT_DONE (1U << 31) /* bist done */ ++#define BT_B2S (1 << 30) /* bist2 ram summary bit */ ++ ++/* intstatus and intmask */ ++#define I_PC (1 << 10) /* pci descriptor error */ ++#define I_PD (1 << 11) /* pci data error */ ++#define I_DE (1 << 12) /* descriptor protocol error */ ++#define I_RU (1 << 13) /* receive descriptor underflow */ ++#define I_RO (1 << 14) /* receive fifo overflow */ ++#define I_XU (1 << 15) /* transmit fifo underflow */ ++#define I_RI (1 << 16) /* receive interrupt */ ++#define I_XI (1 << 24) /* transmit interrupt */ ++ ++/* interrupt receive lazy */ ++#define IRL_TO_MASK 0x00ffffff /* timeout */ ++#define IRL_FC_MASK 0xff000000 /* frame count */ ++#define IRL_FC_SHIFT 24 /* frame count */ ++ ++/*== maccontrol register ==*/ ++#define MCTL_GMODE (1U << 31) ++#define MCTL_DISCARD_PMQ (1 << 30) ++#define MCTL_WAKE (1 << 26) ++#define MCTL_HPS (1 << 25) ++#define MCTL_PROMISC (1 << 24) ++#define MCTL_KEEPBADFCS (1 << 23) ++#define MCTL_KEEPCONTROL (1 << 22) ++#define MCTL_PHYLOCK (1 << 21) ++#define MCTL_BCNS_PROMISC (1 << 20) ++#define MCTL_LOCK_RADIO (1 << 19) ++#define MCTL_AP (1 << 18) ++#define MCTL_INFRA (1 << 17) ++#define MCTL_BIGEND (1 << 16) ++#define MCTL_GPOUT_SEL_MASK (3 << 14) ++#define MCTL_GPOUT_SEL_SHIFT 14 ++#define MCTL_EN_PSMDBG (1 << 13) ++#define MCTL_IHR_EN (1 << 10) ++#define MCTL_SHM_UPPER (1 << 9) ++#define MCTL_SHM_EN (1 << 8) ++#define MCTL_PSM_JMP_0 (1 << 2) ++#define MCTL_PSM_RUN (1 << 1) ++#define MCTL_EN_MAC (1 << 0) ++ ++/*== maccommand register ==*/ ++#define MCMD_BCN0VLD (1 << 0) ++#define MCMD_BCN1VLD (1 << 1) ++#define MCMD_DIRFRMQVAL (1 << 2) ++#define MCMD_CCA (1 << 3) ++#define MCMD_BG_NOISE (1 << 4) ++#define MCMD_SKIP_SHMINIT (1 << 5) /* only used for simulation */ ++#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /* reuse for sample collect */ ++ ++/*== macintstatus/macintmask ==*/ ++/* gracefully suspended */ ++#define MI_MACSSPNDD (1 << 0) ++/* beacon template available */ ++#define MI_BCNTPL (1 << 1) ++/* TBTT indication */ ++#define MI_TBTT (1 << 2) ++/* beacon successfully tx'd */ ++#define MI_BCNSUCCESS (1 << 3) ++/* beacon canceled (IBSS) */ ++#define MI_BCNCANCLD (1 << 4) ++/* end of ATIM-window (IBSS) */ ++#define MI_ATIMWINEND (1 << 5) ++/* PMQ entries available */ ++#define MI_PMQ (1 << 6) ++/* non-specific gen-stat bits that are set by PSM */ ++#define MI_NSPECGEN_0 (1 << 7) ++/* non-specific gen-stat bits that are set by PSM */ ++#define MI_NSPECGEN_1 (1 << 8) ++/* MAC level Tx error */ ++#define MI_MACTXERR (1 << 9) ++/* non-specific gen-stat bits that are set by PSM */ ++#define MI_NSPECGEN_3 (1 << 10) ++/* PHY Tx error */ ++#define MI_PHYTXERR (1 << 11) ++/* Power Management Event */ ++#define MI_PME (1 << 12) ++/* General-purpose timer0 */ ++#define MI_GP0 (1 << 13) ++/* General-purpose timer1 */ ++#define MI_GP1 (1 << 14) ++/* (ORed) DMA-interrupts */ ++#define MI_DMAINT (1 << 15) ++/* MAC has completed a TX FIFO Suspend/Flush */ ++#define MI_TXSTOP (1 << 16) ++/* MAC has completed a CCA measurement */ ++#define MI_CCA (1 << 17) ++/* MAC has collected background noise samples */ ++#define MI_BG_NOISE (1 << 18) ++/* MBSS DTIM TBTT indication */ ++#define MI_DTIM_TBTT (1 << 19) ++/* Probe response queue needs attention */ ++#define MI_PRQ (1 << 20) ++/* Radio/PHY has been powered back up. */ ++#define MI_PWRUP (1 << 21) ++#define MI_RESERVED3 (1 << 22) ++#define MI_RESERVED2 (1 << 23) ++#define MI_RESERVED1 (1 << 25) ++/* MAC detected change on RF Disable input*/ ++#define MI_RFDISABLE (1 << 28) ++/* MAC has completed a TX */ ++#define MI_TFS (1 << 29) ++/* A phy status change wrt G mode */ ++#define MI_PHYCHANGED (1 << 30) ++/* general purpose timeout */ ++#define MI_TO (1U << 31) ++ ++/* Mac capabilities registers */ ++/*== machwcap ==*/ ++#define MCAP_TKIPMIC 0x80000000 /* TKIP MIC hardware present */ ++ ++/*== pmqhost data ==*/ ++/* data entry of head pmq entry */ ++#define PMQH_DATA_MASK 0xffff0000 ++/* PM entry for BSS config */ ++#define PMQH_BSSCFG 0x00100000 ++/* PM Mode OFF: power save off */ ++#define PMQH_PMOFF 0x00010000 ++/* PM Mode ON: power save on */ ++#define PMQH_PMON 0x00020000 ++/* Dis-associated or De-authenticated */ ++#define PMQH_DASAT 0x00040000 ++/* ATIM not acknowledged */ ++#define PMQH_ATIMFAIL 0x00080000 ++/* delete head entry */ ++#define PMQH_DEL_ENTRY 0x00000001 ++/* delete head entry to cur read pointer -1 */ ++#define PMQH_DEL_MULT 0x00000002 ++/* pmq overflow indication */ ++#define PMQH_OFLO 0x00000004 ++/* entries are present in pmq */ ++#define PMQH_NOT_EMPTY 0x00000008 ++ ++/*== phydebug ==*/ ++/* phy is asserting carrier sense */ ++#define PDBG_CRS (1 << 0) ++/* phy is taking xmit byte from mac this cycle */ ++#define PDBG_TXA (1 << 1) ++/* mac is instructing the phy to transmit a frame */ ++#define PDBG_TXF (1 << 2) ++/* phy is signalling a transmit Error to the mac */ ++#define PDBG_TXE (1 << 3) ++/* phy detected the end of a valid frame preamble */ ++#define PDBG_RXF (1 << 4) ++/* phy detected the end of a valid PLCP header */ ++#define PDBG_RXS (1 << 5) ++/* rx start not asserted */ ++#define PDBG_RXFRG (1 << 6) ++/* mac is taking receive byte from phy this cycle */ ++#define PDBG_RXV (1 << 7) ++/* RF portion of the radio is disabled */ ++#define PDBG_RFD (1 << 16) ++ ++/*== objaddr register ==*/ ++#define OBJADDR_SEL_MASK 0x000F0000 ++#define OBJADDR_UCM_SEL 0x00000000 ++#define OBJADDR_SHM_SEL 0x00010000 ++#define OBJADDR_SCR_SEL 0x00020000 ++#define OBJADDR_IHR_SEL 0x00030000 ++#define OBJADDR_RCMTA_SEL 0x00040000 ++#define OBJADDR_SRCHM_SEL 0x00060000 ++#define OBJADDR_WINC 0x01000000 ++#define OBJADDR_RINC 0x02000000 ++#define OBJADDR_AUTO_INC 0x03000000 ++ ++#define WEP_PCMADDR 0x07d4 ++#define WEP_PCMDATA 0x07d6 ++ ++/*== frmtxstatus ==*/ ++#define TXS_V (1 << 0) /* valid bit */ ++#define TXS_STATUS_MASK 0xffff ++#define TXS_FID_MASK 0xffff0000 ++#define TXS_FID_SHIFT 16 ++ ++/*== frmtxstatus2 ==*/ ++#define TXS_SEQ_MASK 0xffff ++#define TXS_PTX_MASK 0xff0000 ++#define TXS_PTX_SHIFT 16 ++#define TXS_MU_MASK 0x01000000 ++#define TXS_MU_SHIFT 24 ++ ++/*== clk_ctl_st ==*/ ++#define CCS_ERSRC_REQ_D11PLL 0x00000100 /* d11 core pll request */ ++#define CCS_ERSRC_REQ_PHYPLL 0x00000200 /* PHY pll request */ ++#define CCS_ERSRC_AVAIL_D11PLL 0x01000000 /* d11 core pll available */ ++#define CCS_ERSRC_AVAIL_PHYPLL 0x02000000 /* PHY pll available */ ++ ++/* HT Cloclk Ctrl and Clock Avail for 4313 */ ++#define CCS_ERSRC_REQ_HT 0x00000010 /* HT avail request */ ++#define CCS_ERSRC_AVAIL_HT 0x00020000 /* HT clock available */ ++ ++/* tsf_cfprep register */ ++#define CFPREP_CBI_MASK 0xffffffc0 ++#define CFPREP_CBI_SHIFT 6 ++#define CFPREP_CFPP 0x00000001 ++ ++/* tx fifo sizes values are in terms of 256 byte blocks */ ++#define TXFIFOCMD_RESET_MASK (1 << 15) /* reset */ ++#define TXFIFOCMD_FIFOSEL_SHIFT 8 /* fifo */ ++#define TXFIFO_FIFOTOP_SHIFT 8 /* fifo start */ ++ ++#define TXFIFO_START_BLK16 65 /* Base address + 32 * 512 B/P */ ++#define TXFIFO_START_BLK 6 /* Base address + 6 * 256 B */ ++#define TXFIFO_SIZE_UNIT 256 /* one unit corresponds to 256 bytes */ ++#define MBSS16_TEMPLMEM_MINBLKS 65 /* one unit corresponds to 256 bytes */ ++ ++/*== phy versions (PhyVersion:Revision field) ==*/ ++/* analog block version */ ++#define PV_AV_MASK 0xf000 ++/* analog block version bitfield offset */ ++#define PV_AV_SHIFT 12 ++/* phy type */ ++#define PV_PT_MASK 0x0f00 ++/* phy type bitfield offset */ ++#define PV_PT_SHIFT 8 ++/* phy version */ ++#define PV_PV_MASK 0x000f ++#define PHY_TYPE(v) ((v & PV_PT_MASK) >> PV_PT_SHIFT) ++ ++/*== phy types (PhyVersion:PhyType field) ==*/ ++#define PHY_TYPE_N 4 /* N-Phy value */ ++#define PHY_TYPE_SSN 6 /* SSLPN-Phy value */ ++#define PHY_TYPE_LCN 8 /* LCN-Phy value */ ++#define PHY_TYPE_LCNXN 9 /* LCNXN-Phy value */ ++#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ ++ ++/*== analog types (PhyVersion:AnalogType field) ==*/ ++#define ANA_11N_013 5 ++ ++/* 802.11a PLCP header def */ ++struct ofdm_phy_hdr { ++ u8 rlpt[3]; /* rate, length, parity, tail */ ++ u16 service; ++ u8 pad; ++} __packed; ++ ++#define D11A_PHY_HDR_GRATE(phdr) ((phdr)->rlpt[0] & 0x0f) ++#define D11A_PHY_HDR_GRES(phdr) (((phdr)->rlpt[0] >> 4) & 0x01) ++#define D11A_PHY_HDR_GLENGTH(phdr) (((u32 *)((phdr)->rlpt) >> 5) & 0x0fff) ++#define D11A_PHY_HDR_GPARITY(phdr) (((phdr)->rlpt[3] >> 1) & 0x01) ++#define D11A_PHY_HDR_GTAIL(phdr) (((phdr)->rlpt[3] >> 2) & 0x3f) ++ ++/* rate encoded per 802.11a-1999 sec 17.3.4.1 */ ++#define D11A_PHY_HDR_SRATE(phdr, rate) \ ++ ((phdr)->rlpt[0] = ((phdr)->rlpt[0] & 0xf0) | ((rate) & 0xf)) ++/* set reserved field to zero */ ++#define D11A_PHY_HDR_SRES(phdr) ((phdr)->rlpt[0] &= 0xef) ++/* length is number of octets in PSDU */ ++#define D11A_PHY_HDR_SLENGTH(phdr, length) \ ++ (*(u32 *)((phdr)->rlpt) = *(u32 *)((phdr)->rlpt) | \ ++ (((length) & 0x0fff) << 5)) ++/* set the tail to all zeros */ ++#define D11A_PHY_HDR_STAIL(phdr) ((phdr)->rlpt[3] &= 0x03) ++ ++#define D11A_PHY_HDR_LEN_L 3 /* low-rate part of PLCP header */ ++#define D11A_PHY_HDR_LEN_R 2 /* high-rate part of PLCP header */ ++ ++#define D11A_PHY_TX_DELAY (2) /* 2.1 usec */ ++ ++#define D11A_PHY_HDR_TIME (4) /* low-rate part of PLCP header */ ++#define D11A_PHY_PRE_TIME (16) ++#define D11A_PHY_PREHDR_TIME (D11A_PHY_PRE_TIME + D11A_PHY_HDR_TIME) ++ ++/* 802.11b PLCP header def */ ++struct cck_phy_hdr { ++ u8 signal; ++ u8 service; ++ u16 length; ++ u16 crc; ++} __packed; ++ ++#define D11B_PHY_HDR_LEN 6 ++ ++#define D11B_PHY_TX_DELAY (3) /* 3.4 usec */ ++ ++#define D11B_PHY_LHDR_TIME (D11B_PHY_HDR_LEN << 3) ++#define D11B_PHY_LPRE_TIME (144) ++#define D11B_PHY_LPREHDR_TIME (D11B_PHY_LPRE_TIME + D11B_PHY_LHDR_TIME) ++ ++#define D11B_PHY_SHDR_TIME (D11B_PHY_LHDR_TIME >> 1) ++#define D11B_PHY_SPRE_TIME (D11B_PHY_LPRE_TIME >> 1) ++#define D11B_PHY_SPREHDR_TIME (D11B_PHY_SPRE_TIME + D11B_PHY_SHDR_TIME) ++ ++#define D11B_PLCP_SIGNAL_LOCKED (1 << 2) ++#define D11B_PLCP_SIGNAL_LE (1 << 7) ++ ++#define MIMO_PLCP_MCS_MASK 0x7f /* mcs index */ ++#define MIMO_PLCP_40MHZ 0x80 /* 40 Hz frame */ ++#define MIMO_PLCP_AMPDU 0x08 /* ampdu */ ++ ++#define BRCMS_GET_CCK_PLCP_LEN(plcp) (plcp[4] + (plcp[5] << 8)) ++#define BRCMS_GET_MIMO_PLCP_LEN(plcp) (plcp[1] + (plcp[2] << 8)) ++#define BRCMS_SET_MIMO_PLCP_LEN(plcp, len) \ ++ do { \ ++ plcp[1] = len & 0xff; \ ++ plcp[2] = ((len >> 8) & 0xff); \ ++ } while (0); ++ ++#define BRCMS_SET_MIMO_PLCP_AMPDU(plcp) (plcp[3] |= MIMO_PLCP_AMPDU) ++#define BRCMS_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU) ++#define BRCMS_IS_MIMO_PLCP_AMPDU(plcp) (plcp[3] & MIMO_PLCP_AMPDU) ++ ++/* ++ * The dot11a PLCP header is 5 bytes. To simplify the software (so that we ++ * don't need e.g. different tx DMA headers for 11a and 11b), the PLCP header ++ * has padding added in the ucode. ++ */ ++#define D11_PHY_HDR_LEN 6 ++ ++/* TX DMA buffer header */ ++struct d11txh { ++ __le16 MacTxControlLow; /* 0x0 */ ++ __le16 MacTxControlHigh; /* 0x1 */ ++ __le16 MacFrameControl; /* 0x2 */ ++ __le16 TxFesTimeNormal; /* 0x3 */ ++ __le16 PhyTxControlWord; /* 0x4 */ ++ __le16 PhyTxControlWord_1; /* 0x5 */ ++ __le16 PhyTxControlWord_1_Fbr; /* 0x6 */ ++ __le16 PhyTxControlWord_1_Rts; /* 0x7 */ ++ __le16 PhyTxControlWord_1_FbrRts; /* 0x8 */ ++ __le16 MainRates; /* 0x9 */ ++ __le16 XtraFrameTypes; /* 0xa */ ++ u8 IV[16]; /* 0x0b - 0x12 */ ++ u8 TxFrameRA[6]; /* 0x13 - 0x15 */ ++ __le16 TxFesTimeFallback; /* 0x16 */ ++ u8 RTSPLCPFallback[6]; /* 0x17 - 0x19 */ ++ __le16 RTSDurFallback; /* 0x1a */ ++ u8 FragPLCPFallback[6]; /* 0x1b - 1d */ ++ __le16 FragDurFallback; /* 0x1e */ ++ __le16 MModeLen; /* 0x1f */ ++ __le16 MModeFbrLen; /* 0x20 */ ++ __le16 TstampLow; /* 0x21 */ ++ __le16 TstampHigh; /* 0x22 */ ++ __le16 ABI_MimoAntSel; /* 0x23 */ ++ __le16 PreloadSize; /* 0x24 */ ++ __le16 AmpduSeqCtl; /* 0x25 */ ++ __le16 TxFrameID; /* 0x26 */ ++ __le16 TxStatus; /* 0x27 */ ++ __le16 MaxNMpdus; /* 0x28 */ ++ __le16 MaxABytes_MRT; /* 0x29 */ ++ __le16 MaxABytes_FBR; /* 0x2a */ ++ __le16 MinMBytes; /* 0x2b */ ++ u8 RTSPhyHeader[D11_PHY_HDR_LEN]; /* 0x2c - 0x2e */ ++ struct ieee80211_rts rts_frame; /* 0x2f - 0x36 */ ++ u16 PAD; /* 0x37 */ ++} __packed; ++ ++#define D11_TXH_LEN 112 /* bytes */ ++ ++/* Frame Types */ ++#define FT_CCK 0 ++#define FT_OFDM 1 ++#define FT_HT 2 ++#define FT_N 3 ++ ++/* ++ * Position of MPDU inside A-MPDU; indicated with bits 10:9 ++ * of MacTxControlLow ++ */ ++#define TXC_AMPDU_SHIFT 9 /* shift for ampdu settings */ ++#define TXC_AMPDU_NONE 0 /* Regular MPDU, not an A-MPDU */ ++#define TXC_AMPDU_FIRST 1 /* first MPDU of an A-MPDU */ ++#define TXC_AMPDU_MIDDLE 2 /* intermediate MPDU of an A-MPDU */ ++#define TXC_AMPDU_LAST 3 /* last (or single) MPDU of an A-MPDU */ ++ ++/*== MacTxControlLow ==*/ ++#define TXC_AMIC 0x8000 ++#define TXC_SENDCTS 0x0800 ++#define TXC_AMPDU_MASK 0x0600 ++#define TXC_BW_40 0x0100 ++#define TXC_FREQBAND_5G 0x0080 ++#define TXC_DFCS 0x0040 ++#define TXC_IGNOREPMQ 0x0020 ++#define TXC_HWSEQ 0x0010 ++#define TXC_STARTMSDU 0x0008 ++#define TXC_SENDRTS 0x0004 ++#define TXC_LONGFRAME 0x0002 ++#define TXC_IMMEDACK 0x0001 ++ ++/*== MacTxControlHigh ==*/ ++/* RTS fallback preamble type 1 = SHORT 0 = LONG */ ++#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000 ++/* RTS main rate preamble type 1 = SHORT 0 = LONG */ ++#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000 ++/* ++ * Main fallback rate preamble type ++ * 1 = SHORT for OFDM/GF for MIMO ++ * 0 = LONG for CCK/MM for MIMO ++ */ ++#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000 ++ ++/* TXC_PREAMBLE_DATA_MAIN is in PhyTxControl bit 5 */ ++/* use fallback rate for this AMPDU */ ++#define TXC_AMPDU_FBR 0x1000 ++#define TXC_SECKEY_MASK 0x0FF0 ++#define TXC_SECKEY_SHIFT 4 ++/* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */ ++#define TXC_ALT_TXPWR 0x0008 ++#define TXC_SECTYPE_MASK 0x0007 ++#define TXC_SECTYPE_SHIFT 0 ++ ++/* Null delimiter for Fallback rate */ ++#define AMPDU_FBR_NULL_DELIM 5 /* Location of Null delimiter count for AMPDU */ ++ ++/* PhyTxControl for Mimophy */ ++#define PHY_TXC_PWR_MASK 0xFC00 ++#define PHY_TXC_PWR_SHIFT 10 ++#define PHY_TXC_ANT_MASK 0x03C0 /* bit 6, 7, 8, 9 */ ++#define PHY_TXC_ANT_SHIFT 6 ++#define PHY_TXC_ANT_0_1 0x00C0 /* auto, last rx */ ++#define PHY_TXC_LCNPHY_ANT_LAST 0x0000 ++#define PHY_TXC_ANT_3 0x0200 /* virtual antenna 3 */ ++#define PHY_TXC_ANT_2 0x0100 /* virtual antenna 2 */ ++#define PHY_TXC_ANT_1 0x0080 /* virtual antenna 1 */ ++#define PHY_TXC_ANT_0 0x0040 /* virtual antenna 0 */ ++#define PHY_TXC_SHORT_HDR 0x0010 ++ ++#define PHY_TXC_OLD_ANT_0 0x0000 ++#define PHY_TXC_OLD_ANT_1 0x0100 ++#define PHY_TXC_OLD_ANT_LAST 0x0300 ++ ++/* PhyTxControl_1 for Mimophy */ ++#define PHY_TXC1_BW_MASK 0x0007 ++#define PHY_TXC1_BW_10MHZ 0 ++#define PHY_TXC1_BW_10MHZ_UP 1 ++#define PHY_TXC1_BW_20MHZ 2 ++#define PHY_TXC1_BW_20MHZ_UP 3 ++#define PHY_TXC1_BW_40MHZ 4 ++#define PHY_TXC1_BW_40MHZ_DUP 5 ++#define PHY_TXC1_MODE_SHIFT 3 ++#define PHY_TXC1_MODE_MASK 0x0038 ++#define PHY_TXC1_MODE_SISO 0 ++#define PHY_TXC1_MODE_CDD 1 ++#define PHY_TXC1_MODE_STBC 2 ++#define PHY_TXC1_MODE_SDM 3 ++ ++/* PhyTxControl for HTphy that are different from Mimophy */ ++#define PHY_TXC_HTANT_MASK 0x3fC0 /* bits 6-13 */ ++ ++/* XtraFrameTypes */ ++#define XFTS_RTS_FT_SHIFT 2 ++#define XFTS_FBRRTS_FT_SHIFT 4 ++#define XFTS_CHANNEL_SHIFT 8 ++ ++/* Antenna diversity bit in ant_wr_settle */ ++#define PHY_AWS_ANTDIV 0x2000 ++ ++/* IFS ctl */ ++#define IFS_USEEDCF (1 << 2) ++ ++/* IFS ctl1 */ ++#define IFS_CTL1_EDCRS (1 << 3) ++#define IFS_CTL1_EDCRS_20L (1 << 4) ++#define IFS_CTL1_EDCRS_40 (1 << 5) ++ ++/* ABI_MimoAntSel */ ++#define ABI_MAS_ADDR_BMP_IDX_MASK 0x0f00 ++#define ABI_MAS_ADDR_BMP_IDX_SHIFT 8 ++#define ABI_MAS_FBR_ANT_PTN_MASK 0x00f0 ++#define ABI_MAS_FBR_ANT_PTN_SHIFT 4 ++#define ABI_MAS_MRT_ANT_PTN_MASK 0x000f ++ ++/* tx status packet */ ++struct tx_status { ++ u16 framelen; ++ u16 PAD; ++ u16 frameid; ++ u16 status; ++ u16 lasttxtime; ++ u16 sequence; ++ u16 phyerr; ++ u16 ackphyrxsh; ++} __packed; ++ ++#define TXSTATUS_LEN 16 ++ ++/* status field bit definitions */ ++#define TX_STATUS_FRM_RTX_MASK 0xF000 ++#define TX_STATUS_FRM_RTX_SHIFT 12 ++#define TX_STATUS_RTS_RTX_MASK 0x0F00 ++#define TX_STATUS_RTS_RTX_SHIFT 8 ++#define TX_STATUS_MASK 0x00FE ++#define TX_STATUS_PMINDCTD (1 << 7) /* PM mode indicated to AP */ ++#define TX_STATUS_INTERMEDIATE (1 << 6) /* intermediate or 1st ampdu pkg */ ++#define TX_STATUS_AMPDU (1 << 5) /* AMPDU status */ ++#define TX_STATUS_SUPR_MASK 0x1C /* suppress status bits (4:2) */ ++#define TX_STATUS_SUPR_SHIFT 2 ++#define TX_STATUS_ACK_RCV (1 << 1) /* ACK received */ ++#define TX_STATUS_VALID (1 << 0) /* Tx status valid */ ++#define TX_STATUS_NO_ACK 0 ++ ++/* suppress status reason codes */ ++#define TX_STATUS_SUPR_PMQ (1 << 2) /* PMQ entry */ ++#define TX_STATUS_SUPR_FLUSH (2 << 2) /* flush request */ ++#define TX_STATUS_SUPR_FRAG (3 << 2) /* previous frag failure */ ++#define TX_STATUS_SUPR_TBTT (3 << 2) /* SHARED: Probe resp supr for TBTT */ ++#define TX_STATUS_SUPR_BADCH (4 << 2) /* channel mismatch */ ++#define TX_STATUS_SUPR_EXPTIME (5 << 2) /* lifetime expiry */ ++#define TX_STATUS_SUPR_UF (6 << 2) /* underflow */ ++ ++/* Unexpected tx status for rate update */ ++#define TX_STATUS_UNEXP(status) \ ++ ((((status) & TX_STATUS_INTERMEDIATE) != 0) && \ ++ TX_STATUS_UNEXP_AMPDU(status)) ++ ++/* Unexpected tx status for A-MPDU rate update */ ++#define TX_STATUS_UNEXP_AMPDU(status) \ ++ ((((status) & TX_STATUS_SUPR_MASK) != 0) && \ ++ (((status) & TX_STATUS_SUPR_MASK) != TX_STATUS_SUPR_EXPTIME)) ++ ++#define TX_STATUS_BA_BMAP03_MASK 0xF000 /* ba bitmap 0:3 in 1st pkg */ ++#define TX_STATUS_BA_BMAP03_SHIFT 12 /* ba bitmap 0:3 in 1st pkg */ ++#define TX_STATUS_BA_BMAP47_MASK 0x001E /* ba bitmap 4:7 in 2nd pkg */ ++#define TX_STATUS_BA_BMAP47_SHIFT 3 /* ba bitmap 4:7 in 2nd pkg */ ++ ++/* RXE (Receive Engine) */ ++ ++/* RCM_CTL */ ++#define RCM_INC_MASK_H 0x0080 ++#define RCM_INC_MASK_L 0x0040 ++#define RCM_INC_DATA 0x0020 ++#define RCM_INDEX_MASK 0x001F ++#define RCM_SIZE 15 ++ ++#define RCM_MAC_OFFSET 0 /* current MAC address */ ++#define RCM_BSSID_OFFSET 3 /* current BSSID address */ ++#define RCM_F_BSSID_0_OFFSET 6 /* foreign BSS CFP tracking */ ++#define RCM_F_BSSID_1_OFFSET 9 /* foreign BSS CFP tracking */ ++#define RCM_F_BSSID_2_OFFSET 12 /* foreign BSS CFP tracking */ ++ ++#define RCM_WEP_TA0_OFFSET 16 ++#define RCM_WEP_TA1_OFFSET 19 ++#define RCM_WEP_TA2_OFFSET 22 ++#define RCM_WEP_TA3_OFFSET 25 ++ ++/* PSM Block */ ++ ++/* psm_phy_hdr_param bits */ ++#define MAC_PHY_RESET 1 ++#define MAC_PHY_CLOCK_EN 2 ++#define MAC_PHY_FORCE_CLK 4 ++ ++/* WEP Block */ ++ ++/* WEP_WKEY */ ++#define WKEY_START (1 << 8) ++#define WKEY_SEL_MASK 0x1F ++ ++/* WEP data formats */ ++ ++/* the number of RCMTA entries */ ++#define RCMTA_SIZE 50 ++ ++#define M_ADDR_BMP_BLK (0x37e * 2) ++#define M_ADDR_BMP_BLK_SZ 12 ++ ++#define ADDR_BMP_RA (1 << 0) /* Receiver Address (RA) */ ++#define ADDR_BMP_TA (1 << 1) /* Transmitter Address (TA) */ ++#define ADDR_BMP_BSSID (1 << 2) /* BSSID */ ++#define ADDR_BMP_AP (1 << 3) /* Infra-BSS Access Point */ ++#define ADDR_BMP_STA (1 << 4) /* Infra-BSS Station */ ++#define ADDR_BMP_RESERVED1 (1 << 5) ++#define ADDR_BMP_RESERVED2 (1 << 6) ++#define ADDR_BMP_RESERVED3 (1 << 7) ++#define ADDR_BMP_BSS_IDX_MASK (3 << 8) /* BSS control block index */ ++#define ADDR_BMP_BSS_IDX_SHIFT 8 ++ ++#define WSEC_MAX_RCMTA_KEYS 54 ++ ++/* max keys in M_TKMICKEYS_BLK */ ++#define WSEC_MAX_TKMIC_ENGINE_KEYS 12 /* 8 + 4 default */ ++ ++/* max RXE match registers */ ++#define WSEC_MAX_RXE_KEYS 4 ++ ++/* SECKINDXALGO (Security Key Index & Algorithm Block) word format */ ++/* SKL (Security Key Lookup) */ ++#define SKL_ALGO_MASK 0x0007 ++#define SKL_ALGO_SHIFT 0 ++#define SKL_KEYID_MASK 0x0008 ++#define SKL_KEYID_SHIFT 3 ++#define SKL_INDEX_MASK 0x03F0 ++#define SKL_INDEX_SHIFT 4 ++#define SKL_GRP_ALGO_MASK 0x1c00 ++#define SKL_GRP_ALGO_SHIFT 10 ++ ++/* additional bits defined for IBSS group key support */ ++#define SKL_IBSS_INDEX_MASK 0x01F0 ++#define SKL_IBSS_INDEX_SHIFT 4 ++#define SKL_IBSS_KEYID1_MASK 0x0600 ++#define SKL_IBSS_KEYID1_SHIFT 9 ++#define SKL_IBSS_KEYID2_MASK 0x1800 ++#define SKL_IBSS_KEYID2_SHIFT 11 ++#define SKL_IBSS_KEYALGO_MASK 0xE000 ++#define SKL_IBSS_KEYALGO_SHIFT 13 ++ ++#define WSEC_MODE_OFF 0 ++#define WSEC_MODE_HW 1 ++#define WSEC_MODE_SW 2 ++ ++#define WSEC_ALGO_OFF 0 ++#define WSEC_ALGO_WEP1 1 ++#define WSEC_ALGO_TKIP 2 ++#define WSEC_ALGO_AES 3 ++#define WSEC_ALGO_WEP128 4 ++#define WSEC_ALGO_AES_LEGACY 5 ++#define WSEC_ALGO_NALG 6 ++ ++#define AES_MODE_NONE 0 ++#define AES_MODE_CCM 1 ++ ++/* WEP_CTL (Rev 0) */ ++#define WECR0_KEYREG_SHIFT 0 ++#define WECR0_KEYREG_MASK 0x7 ++#define WECR0_DECRYPT (1 << 3) ++#define WECR0_IVINLINE (1 << 4) ++#define WECR0_WEPALG_SHIFT 5 ++#define WECR0_WEPALG_MASK (0x7 << 5) ++#define WECR0_WKEYSEL_SHIFT 8 ++#define WECR0_WKEYSEL_MASK (0x7 << 8) ++#define WECR0_WKEYSTART (1 << 11) ++#define WECR0_WEPINIT (1 << 14) ++#define WECR0_ICVERR (1 << 15) ++ ++/* Frame template map byte offsets */ ++#define T_ACTS_TPL_BASE (0) ++#define T_NULL_TPL_BASE (0xc * 2) ++#define T_QNULL_TPL_BASE (0x1c * 2) ++#define T_RR_TPL_BASE (0x2c * 2) ++#define T_BCN0_TPL_BASE (0x34 * 2) ++#define T_PRS_TPL_BASE (0x134 * 2) ++#define T_BCN1_TPL_BASE (0x234 * 2) ++#define T_TX_FIFO_TXRAM_BASE (T_ACTS_TPL_BASE + \ ++ (TXFIFO_START_BLK * TXFIFO_SIZE_UNIT)) ++ ++#define T_BA_TPL_BASE T_QNULL_TPL_BASE /* template area for BA */ ++ ++#define T_RAM_ACCESS_SZ 4 /* template ram is 4 byte access only */ ++ ++/* Shared Mem byte offsets */ ++ ++/* Location where the ucode expects the corerev */ ++#define M_MACHW_VER (0x00b * 2) ++ ++/* Location where the ucode expects the MAC capabilities */ ++#define M_MACHW_CAP_L (0x060 * 2) ++#define M_MACHW_CAP_H (0x061 * 2) ++ ++/* WME shared memory */ ++#define M_EDCF_STATUS_OFF (0x007 * 2) ++#define M_TXF_CUR_INDEX (0x018 * 2) ++#define M_EDCF_QINFO (0x120 * 2) ++ ++/* PS-mode related parameters */ ++#define M_DOT11_SLOT (0x008 * 2) ++#define M_DOT11_DTIMPERIOD (0x009 * 2) ++#define M_NOSLPZNATDTIM (0x026 * 2) ++ ++/* Beacon-related parameters */ ++#define M_BCN0_FRM_BYTESZ (0x00c * 2) /* Bcn 0 template length */ ++#define M_BCN1_FRM_BYTESZ (0x00d * 2) /* Bcn 1 template length */ ++#define M_BCN_TXTSF_OFFSET (0x00e * 2) ++#define M_TIMBPOS_INBEACON (0x00f * 2) ++#define M_SFRMTXCNTFBRTHSD (0x022 * 2) ++#define M_LFRMTXCNTFBRTHSD (0x023 * 2) ++#define M_BCN_PCTLWD (0x02a * 2) ++#define M_BCN_LI (0x05b * 2) /* beacon listen interval */ ++ ++/* MAX Rx Frame len */ ++#define M_MAXRXFRM_LEN (0x010 * 2) ++ ++/* ACK/CTS related params */ ++#define M_RSP_PCTLWD (0x011 * 2) ++ ++/* Hardware Power Control */ ++#define M_TXPWR_N (0x012 * 2) ++#define M_TXPWR_TARGET (0x013 * 2) ++#define M_TXPWR_MAX (0x014 * 2) ++#define M_TXPWR_CUR (0x019 * 2) ++ ++/* Rx-related parameters */ ++#define M_RX_PAD_DATA_OFFSET (0x01a * 2) ++ ++/* WEP Shared mem data */ ++#define M_SEC_DEFIVLOC (0x01e * 2) ++#define M_SEC_VALNUMSOFTMCHTA (0x01f * 2) ++#define M_PHYVER (0x028 * 2) ++#define M_PHYTYPE (0x029 * 2) ++#define M_SECRXKEYS_PTR (0x02b * 2) ++#define M_TKMICKEYS_PTR (0x059 * 2) ++#define M_SECKINDXALGO_BLK (0x2ea * 2) ++#define M_SECKINDXALGO_BLK_SZ 54 ++#define M_SECPSMRXTAMCH_BLK (0x2fa * 2) ++#define M_TKIP_TSC_TTAK (0x18c * 2) ++#define D11_MAX_KEY_SIZE 16 ++ ++#define M_MAX_ANTCNT (0x02e * 2) /* antenna swap threshold */ ++ ++/* Probe response related parameters */ ++#define M_SSIDLEN (0x024 * 2) ++#define M_PRB_RESP_FRM_LEN (0x025 * 2) ++#define M_PRS_MAXTIME (0x03a * 2) ++#define M_SSID (0xb0 * 2) ++#define M_CTXPRS_BLK (0xc0 * 2) ++#define C_CTX_PCTLWD_POS (0x4 * 2) ++ ++/* Delta between OFDM and CCK power in CCK power boost mode */ ++#define M_OFDM_OFFSET (0x027 * 2) ++ ++/* TSSI for last 4 11b/g CCK packets transmitted */ ++#define M_B_TSSI_0 (0x02c * 2) ++#define M_B_TSSI_1 (0x02d * 2) ++ ++/* Host flags to turn on ucode options */ ++#define M_HOST_FLAGS1 (0x02f * 2) ++#define M_HOST_FLAGS2 (0x030 * 2) ++#define M_HOST_FLAGS3 (0x031 * 2) ++#define M_HOST_FLAGS4 (0x03c * 2) ++#define M_HOST_FLAGS5 (0x06a * 2) ++#define M_HOST_FLAGS_SZ 16 ++ ++#define M_RADAR_REG (0x033 * 2) ++ ++/* TSSI for last 4 11a OFDM packets transmitted */ ++#define M_A_TSSI_0 (0x034 * 2) ++#define M_A_TSSI_1 (0x035 * 2) ++ ++/* noise interference measurement */ ++#define M_NOISE_IF_COUNT (0x034 * 2) ++#define M_NOISE_IF_TIMEOUT (0x035 * 2) ++ ++#define M_RF_RX_SP_REG1 (0x036 * 2) ++ ++/* TSSI for last 4 11g OFDM packets transmitted */ ++#define M_G_TSSI_0 (0x038 * 2) ++#define M_G_TSSI_1 (0x039 * 2) ++ ++/* Background noise measure */ ++#define M_JSSI_0 (0x44 * 2) ++#define M_JSSI_1 (0x45 * 2) ++#define M_JSSI_AUX (0x46 * 2) ++ ++#define M_CUR_2050_RADIOCODE (0x47 * 2) ++ ++/* TX fifo sizes */ ++#define M_FIFOSIZE0 (0x4c * 2) ++#define M_FIFOSIZE1 (0x4d * 2) ++#define M_FIFOSIZE2 (0x4e * 2) ++#define M_FIFOSIZE3 (0x4f * 2) ++#define D11_MAX_TX_FRMS 32 /* max frames allowed in tx fifo */ ++ ++/* Current channel number plus upper bits */ ++#define M_CURCHANNEL (0x50 * 2) ++#define D11_CURCHANNEL_5G 0x0100; ++#define D11_CURCHANNEL_40 0x0200; ++#define D11_CURCHANNEL_MAX 0x00FF; ++ ++/* last posted frameid on the bcmc fifo */ ++#define M_BCMC_FID (0x54 * 2) ++#define INVALIDFID 0xffff ++ ++/* extended beacon phyctl bytes for 11N */ ++#define M_BCN_PCTL1WD (0x058 * 2) ++ ++/* idle busy ratio to duty_cycle requirement */ ++#define M_TX_IDLE_BUSY_RATIO_X_16_CCK (0x52 * 2) ++#define M_TX_IDLE_BUSY_RATIO_X_16_OFDM (0x5A * 2) ++ ++/* CW RSSI for LCNPHY */ ++#define M_LCN_RSSI_0 0x1332 ++#define M_LCN_RSSI_1 0x1338 ++#define M_LCN_RSSI_2 0x133e ++#define M_LCN_RSSI_3 0x1344 ++ ++/* SNR for LCNPHY */ ++#define M_LCN_SNR_A_0 0x1334 ++#define M_LCN_SNR_B_0 0x1336 ++ ++#define M_LCN_SNR_A_1 0x133a ++#define M_LCN_SNR_B_1 0x133c ++ ++#define M_LCN_SNR_A_2 0x1340 ++#define M_LCN_SNR_B_2 0x1342 ++ ++#define M_LCN_SNR_A_3 0x1346 ++#define M_LCN_SNR_B_3 0x1348 ++ ++#define M_LCN_LAST_RESET (81*2) ++#define M_LCN_LAST_LOC (63*2) ++#define M_LCNPHY_RESET_STATUS (4902) ++#define M_LCNPHY_DSC_TIME (0x98d*2) ++#define M_LCNPHY_RESET_CNT_DSC (0x98b*2) ++#define M_LCNPHY_RESET_CNT (0x98c*2) ++ ++/* Rate table offsets */ ++#define M_RT_DIRMAP_A (0xe0 * 2) ++#define M_RT_BBRSMAP_A (0xf0 * 2) ++#define M_RT_DIRMAP_B (0x100 * 2) ++#define M_RT_BBRSMAP_B (0x110 * 2) ++ ++/* Rate table entry offsets */ ++#define M_RT_PRS_PLCP_POS 10 ++#define M_RT_PRS_DUR_POS 16 ++#define M_RT_OFDM_PCTL1_POS 18 ++ ++#define M_20IN40_IQ (0x380 * 2) ++ ++/* SHM locations where ucode stores the current power index */ ++#define M_CURR_IDX1 (0x384 * 2) ++#define M_CURR_IDX2 (0x387 * 2) ++ ++#define M_BSCALE_ANT0 (0x5e * 2) ++#define M_BSCALE_ANT1 (0x5f * 2) ++ ++/* Antenna Diversity Testing */ ++#define M_MIMO_ANTSEL_RXDFLT (0x63 * 2) ++#define M_ANTSEL_CLKDIV (0x61 * 2) ++#define M_MIMO_ANTSEL_TXDFLT (0x64 * 2) ++ ++#define M_MIMO_MAXSYM (0x5d * 2) ++#define MIMO_MAXSYM_DEF 0x8000 /* 32k */ ++#define MIMO_MAXSYM_MAX 0xffff /* 64k */ ++ ++#define M_WATCHDOG_8TU (0x1e * 2) ++#define WATCHDOG_8TU_DEF 5 ++#define WATCHDOG_8TU_MAX 10 ++ ++/* Manufacturing Test Variables */ ++/* PER test mode */ ++#define M_PKTENG_CTRL (0x6c * 2) ++/* IFS for TX mode */ ++#define M_PKTENG_IFS (0x6d * 2) ++/* Lower word of tx frmcnt/rx lostcnt */ ++#define M_PKTENG_FRMCNT_LO (0x6e * 2) ++/* Upper word of tx frmcnt/rx lostcnt */ ++#define M_PKTENG_FRMCNT_HI (0x6f * 2) ++ ++/* Index variation in vbat ripple */ ++#define M_LCN_PWR_IDX_MAX (0x67 * 2) /* highest index read by ucode */ ++#define M_LCN_PWR_IDX_MIN (0x66 * 2) /* lowest index read by ucode */ ++ ++/* M_PKTENG_CTRL bit definitions */ ++#define M_PKTENG_MODE_TX 0x0001 ++#define M_PKTENG_MODE_TX_RIFS 0x0004 ++#define M_PKTENG_MODE_TX_CTS 0x0008 ++#define M_PKTENG_MODE_RX 0x0002 ++#define M_PKTENG_MODE_RX_WITH_ACK 0x0402 ++#define M_PKTENG_MODE_MASK 0x0003 ++/* TX frames indicated in the frmcnt reg */ ++#define M_PKTENG_FRMCNT_VLD 0x0100 ++ ++/* Sample Collect parameters (bitmap and type) */ ++/* Trigger bitmap for sample collect */ ++#define M_SMPL_COL_BMP (0x37d * 2) ++/* Sample collect type */ ++#define M_SMPL_COL_CTL (0x3b2 * 2) ++ ++#define ANTSEL_CLKDIV_4MHZ 6 ++#define MIMO_ANTSEL_BUSY 0x4000 /* bit 14 (busy) */ ++#define MIMO_ANTSEL_SEL 0x8000 /* bit 15 write the value */ ++#define MIMO_ANTSEL_WAIT 50 /* 50us wait */ ++#define MIMO_ANTSEL_OVERRIDE 0x8000 /* flag */ ++ ++struct shm_acparams { ++ u16 txop; ++ u16 cwmin; ++ u16 cwmax; ++ u16 cwcur; ++ u16 aifs; ++ u16 bslots; ++ u16 reggap; ++ u16 status; ++ u16 rsvd[8]; ++} __packed; ++#define M_EDCF_QLEN (16 * 2) ++ ++#define WME_STATUS_NEWAC (1 << 8) ++ ++/* M_HOST_FLAGS */ ++#define MHFMAX 5 /* Number of valid hostflag half-word (u16) */ ++#define MHF1 0 /* Hostflag 1 index */ ++#define MHF2 1 /* Hostflag 2 index */ ++#define MHF3 2 /* Hostflag 3 index */ ++#define MHF4 3 /* Hostflag 4 index */ ++#define MHF5 4 /* Hostflag 5 index */ ++ ++/* Flags in M_HOST_FLAGS */ ++/* Enable ucode antenna diversity help */ ++#define MHF1_ANTDIV 0x0001 ++/* Enable EDCF access control */ ++#define MHF1_EDCF 0x0100 ++#define MHF1_IQSWAP_WAR 0x0200 ++/* Disable Slow clock request, for corerev < 11 */ ++#define MHF1_FORCEFASTCLK 0x0400 ++ ++/* Flags in M_HOST_FLAGS2 */ ++ ++/* Flush BCMC FIFO immediately */ ++#define MHF2_TXBCMC_NOW 0x0040 ++/* Enable ucode/hw power control */ ++#define MHF2_HWPWRCTL 0x0080 ++#define MHF2_NPHY40MHZ_WAR 0x0800 ++ ++/* Flags in M_HOST_FLAGS3 */ ++/* enabled mimo antenna selection */ ++#define MHF3_ANTSEL_EN 0x0001 ++/* antenna selection mode: 0: 2x3, 1: 2x4 */ ++#define MHF3_ANTSEL_MODE 0x0002 ++#define MHF3_RESERVED1 0x0004 ++#define MHF3_RESERVED2 0x0008 ++#define MHF3_NPHY_MLADV_WAR 0x0010 ++ ++/* Flags in M_HOST_FLAGS4 */ ++/* force bphy Tx on core 0 (board level WAR) */ ++#define MHF4_BPHY_TXCORE0 0x0080 ++/* for 4313A0 FEM boards */ ++#define MHF4_EXTPA_ENABLE 0x4000 ++ ++/* Flags in M_HOST_FLAGS5 */ ++#define MHF5_4313_GPIOCTRL 0x0001 ++#define MHF5_RESERVED1 0x0002 ++#define MHF5_RESERVED2 0x0004 ++/* Radio power setting for ucode */ ++#define M_RADIO_PWR (0x32 * 2) ++ ++/* phy noise recorded by ucode right after tx */ ++#define M_PHY_NOISE (0x037 * 2) ++#define PHY_NOISE_MASK 0x00ff ++ ++/* ++ * Receive Frame Data Header for 802.11b DCF-only frames ++ * ++ * RxFrameSize: Actual byte length of the frame data received ++ * PAD: padding (not used) ++ * PhyRxStatus_0: PhyRxStatus 15:0 ++ * PhyRxStatus_1: PhyRxStatus 31:16 ++ * PhyRxStatus_2: PhyRxStatus 47:32 ++ * PhyRxStatus_3: PhyRxStatus 63:48 ++ * PhyRxStatus_4: PhyRxStatus 79:64 ++ * PhyRxStatus_5: PhyRxStatus 95:80 ++ * RxStatus1: MAC Rx Status ++ * RxStatus2: extended MAC Rx status ++ * RxTSFTime: RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY ++ * RxChan: gain code, channel radio code, and phy type ++ */ ++struct d11rxhdr_le { ++ __le16 RxFrameSize; ++ u16 PAD; ++ __le16 PhyRxStatus_0; ++ __le16 PhyRxStatus_1; ++ __le16 PhyRxStatus_2; ++ __le16 PhyRxStatus_3; ++ __le16 PhyRxStatus_4; ++ __le16 PhyRxStatus_5; ++ __le16 RxStatus1; ++ __le16 RxStatus2; ++ __le16 RxTSFTime; ++ __le16 RxChan; ++} __packed; ++ ++struct d11rxhdr { ++ u16 RxFrameSize; ++ u16 PAD; ++ u16 PhyRxStatus_0; ++ u16 PhyRxStatus_1; ++ u16 PhyRxStatus_2; ++ u16 PhyRxStatus_3; ++ u16 PhyRxStatus_4; ++ u16 PhyRxStatus_5; ++ u16 RxStatus1; ++ u16 RxStatus2; ++ u16 RxTSFTime; ++ u16 RxChan; ++} __packed; ++ ++/* PhyRxStatus_0: */ ++/* NPHY only: CCK, OFDM, preN, N */ ++#define PRXS0_FT_MASK 0x0003 ++/* NPHY only: clip count adjustment steps by AGC */ ++#define PRXS0_CLIP_MASK 0x000C ++#define PRXS0_CLIP_SHIFT 2 ++/* PHY received a frame with unsupported rate */ ++#define PRXS0_UNSRATE 0x0010 ++/* GPHY: rx ant, NPHY: upper sideband */ ++#define PRXS0_RXANT_UPSUBBAND 0x0020 ++/* CCK frame only: lost crs during cck frame reception */ ++#define PRXS0_LCRS 0x0040 ++/* Short Preamble */ ++#define PRXS0_SHORTH 0x0080 ++/* PLCP violation */ ++#define PRXS0_PLCPFV 0x0100 ++/* PLCP header integrity check failed */ ++#define PRXS0_PLCPHCF 0x0200 ++/* legacy PHY gain control */ ++#define PRXS0_GAIN_CTL 0x4000 ++/* NPHY: Antennas used for received frame, bitmask */ ++#define PRXS0_ANTSEL_MASK 0xF000 ++#define PRXS0_ANTSEL_SHIFT 0x12 ++ ++/* subfield PRXS0_FT_MASK */ ++#define PRXS0_CCK 0x0000 ++/* valid only for G phy, use rxh->RxChan for A phy */ ++#define PRXS0_OFDM 0x0001 ++#define PRXS0_PREN 0x0002 ++#define PRXS0_STDN 0x0003 ++ ++/* subfield PRXS0_ANTSEL_MASK */ ++#define PRXS0_ANTSEL_0 0x0 /* antenna 0 is used */ ++#define PRXS0_ANTSEL_1 0x2 /* antenna 1 is used */ ++#define PRXS0_ANTSEL_2 0x4 /* antenna 2 is used */ ++#define PRXS0_ANTSEL_3 0x8 /* antenna 3 is used */ ++ ++/* PhyRxStatus_1: */ ++#define PRXS1_JSSI_MASK 0x00FF ++#define PRXS1_JSSI_SHIFT 0 ++#define PRXS1_SQ_MASK 0xFF00 ++#define PRXS1_SQ_SHIFT 8 ++ ++/* nphy PhyRxStatus_1: */ ++#define PRXS1_nphy_PWR0_MASK 0x00FF ++#define PRXS1_nphy_PWR1_MASK 0xFF00 ++ ++/* HTPHY Rx Status defines */ ++/* htphy PhyRxStatus_0: those bit are overlapped with PhyRxStatus_0 */ ++#define PRXS0_BAND 0x0400 /* 0 = 2.4G, 1 = 5G */ ++#define PRXS0_RSVD 0x0800 /* reserved; set to 0 */ ++#define PRXS0_UNUSED 0xF000 /* unused and not defined; set to 0 */ ++ ++/* htphy PhyRxStatus_1: */ ++/* core enables for {3..0}, 0=disabled, 1=enabled */ ++#define PRXS1_HTPHY_CORE_MASK 0x000F ++/* antenna configation */ ++#define PRXS1_HTPHY_ANTCFG_MASK 0x00F0 ++/* Mixmode PLCP Length low byte mask */ ++#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00 ++ ++/* htphy PhyRxStatus_2: */ ++/* Mixmode PLCP Length high byte maskw */ ++#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F ++/* Mixmode PLCP rate mask */ ++#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0 ++/* Rx power on core 0 */ ++#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00 ++ ++/* htphy PhyRxStatus_3: */ ++/* Rx power on core 1 */ ++#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF ++/* Rx power on core 2 */ ++#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00 ++ ++/* htphy PhyRxStatus_4: */ ++/* Rx power on core 3 */ ++#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF ++/* Coarse frequency offset */ ++#define PRXS4_HTPHY_CFO 0xFF00 ++ ++/* htphy PhyRxStatus_5: */ ++/* Fine frequency offset */ ++#define PRXS5_HTPHY_FFO 0x00FF ++/* Advance Retard */ ++#define PRXS5_HTPHY_AR 0xFF00 ++ ++#define HTPHY_MMPLCPLen(rxs) \ ++ ((((rxs)->PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \ ++ (((rxs)->PhyRxStatus_2 & PRXS2_HTPHY_MMPLCPLenH_MASK) << 8)) ++/* Get Rx power on core 0 */ ++#define HTPHY_RXPWR_ANT0(rxs) \ ++ ((((rxs)->PhyRxStatus_2) & PRXS2_HTPHY_RXPWR_ANT0) >> 8) ++/* Get Rx power on core 1 */ ++#define HTPHY_RXPWR_ANT1(rxs) \ ++ (((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT1) ++/* Get Rx power on core 2 */ ++#define HTPHY_RXPWR_ANT2(rxs) \ ++ ((((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT2) >> 8) ++ ++/* ucode RxStatus1: */ ++#define RXS_BCNSENT 0x8000 ++#define RXS_SECKINDX_MASK 0x07e0 ++#define RXS_SECKINDX_SHIFT 5 ++#define RXS_DECERR (1 << 4) ++#define RXS_DECATMPT (1 << 3) ++/* PAD bytes to make IP data 4 bytes aligned */ ++#define RXS_PBPRES (1 << 2) ++#define RXS_RESPFRAMETX (1 << 1) ++#define RXS_FCSERR (1 << 0) ++ ++/* ucode RxStatus2: */ ++#define RXS_AMSDU_MASK 1 ++#define RXS_AGGTYPE_MASK 0x6 ++#define RXS_AGGTYPE_SHIFT 1 ++#define RXS_PHYRXST_VALID (1 << 8) ++#define RXS_RXANT_MASK 0x3 ++#define RXS_RXANT_SHIFT 12 ++ ++/* RxChan */ ++#define RXS_CHAN_40 0x1000 ++#define RXS_CHAN_5G 0x0800 ++#define RXS_CHAN_ID_MASK 0x07f8 ++#define RXS_CHAN_ID_SHIFT 3 ++#define RXS_CHAN_PHYTYPE_MASK 0x0007 ++#define RXS_CHAN_PHYTYPE_SHIFT 0 ++ ++/* Index of attenuations used during ucode power control. */ ++#define M_PWRIND_BLKS (0x184 * 2) ++#define M_PWRIND_MAP0 (M_PWRIND_BLKS + 0x0) ++#define M_PWRIND_MAP1 (M_PWRIND_BLKS + 0x2) ++#define M_PWRIND_MAP2 (M_PWRIND_BLKS + 0x4) ++#define M_PWRIND_MAP3 (M_PWRIND_BLKS + 0x6) ++/* M_PWRIND_MAP(core) macro */ ++#define M_PWRIND_MAP(core) (M_PWRIND_BLKS + ((core)<<1)) ++ ++/* PSM SHM variable offsets */ ++#define M_PSM_SOFT_REGS 0x0 ++#define M_BOM_REV_MAJOR (M_PSM_SOFT_REGS + 0x0) ++#define M_BOM_REV_MINOR (M_PSM_SOFT_REGS + 0x2) ++#define M_UCODE_DBGST (M_PSM_SOFT_REGS + 0x40) /* ucode debug status code */ ++#define M_UCODE_MACSTAT (M_PSM_SOFT_REGS + 0xE0) /* macstat counters */ ++ ++#define M_AGING_THRSH (0x3e * 2) /* max time waiting for medium before tx */ ++#define M_MBURST_SIZE (0x40 * 2) /* max frames in a frameburst */ ++#define M_MBURST_TXOP (0x41 * 2) /* max frameburst TXOP in unit of us */ ++#define M_SYNTHPU_DLY (0x4a * 2) /* pre-wakeup for synthpu, default: 500 */ ++#define M_PRETBTT (0x4b * 2) ++ ++/* offset to the target txpwr */ ++#define M_ALT_TXPWR_IDX (M_PSM_SOFT_REGS + (0x3b * 2)) ++#define M_PHY_TX_FLT_PTR (M_PSM_SOFT_REGS + (0x3d * 2)) ++#define M_CTS_DURATION (M_PSM_SOFT_REGS + (0x5c * 2)) ++#define M_LP_RCCAL_OVR (M_PSM_SOFT_REGS + (0x6b * 2)) ++ ++/* PKTENG Rx Stats Block */ ++#define M_RXSTATS_BLK_PTR (M_PSM_SOFT_REGS + (0x65 * 2)) ++ ++/* ucode debug status codes */ ++/* not valid really */ ++#define DBGST_INACTIVE 0 ++/* after zeroing SHM, before suspending at init */ ++#define DBGST_INIT 1 ++/* "normal" state */ ++#define DBGST_ACTIVE 2 ++/* suspended */ ++#define DBGST_SUSPENDED 3 ++/* asleep (PS mode) */ ++#define DBGST_ASLEEP 4 ++ ++/* Scratch Reg defs */ ++enum _ePsmScratchPadRegDefinitions { ++ S_RSV0 = 0, ++ S_RSV1, ++ S_RSV2, ++ ++ /* offset 0x03: scratch registers for Dot11-contants */ ++ S_DOT11_CWMIN, /* CW-minimum */ ++ S_DOT11_CWMAX, /* CW-maximum */ ++ S_DOT11_CWCUR, /* CW-current */ ++ S_DOT11_SRC_LMT, /* short retry count limit */ ++ S_DOT11_LRC_LMT, /* long retry count limit */ ++ S_DOT11_DTIMCOUNT, /* DTIM-count */ ++ ++ /* offset 0x09: Tx-side scratch registers */ ++ S_SEQ_NUM, /* hardware sequence number reg */ ++ S_SEQ_NUM_FRAG, /* seq num for frags (at the start of MSDU) */ ++ S_FRMRETX_CNT, /* frame retx count */ ++ S_SSRC, /* Station short retry count */ ++ S_SLRC, /* Station long retry count */ ++ S_EXP_RSP, /* Expected response frame */ ++ S_OLD_BREM, /* Remaining backoff ctr */ ++ S_OLD_CWWIN, /* saved-off CW-cur */ ++ S_TXECTL, /* TXE-Ctl word constructed in scr-pad */ ++ S_CTXTST, /* frm type-subtype as read from Tx-descr */ ++ ++ /* offset 0x13: Rx-side scratch registers */ ++ S_RXTST, /* Type and subtype in Rxframe */ ++ ++ /* Global state register */ ++ S_STREG, /* state storage actual bit maps below */ ++ ++ S_TXPWR_SUM, /* Tx power control: accumulator */ ++ S_TXPWR_ITER, /* Tx power control: iteration */ ++ S_RX_FRMTYPE, /* Rate and PHY type for frames */ ++ S_THIS_AGG, /* Size of this AGG (A-MSDU) */ ++ ++ S_KEYINDX, ++ S_RXFRMLEN, /* Receive MPDU length in bytes */ ++ ++ /* offset 0x1B: Receive TSF time stored in SCR */ ++ S_RXTSFTMRVAL_WD3, /* TSF value at the start of rx */ ++ S_RXTSFTMRVAL_WD2, /* TSF value at the start of rx */ ++ S_RXTSFTMRVAL_WD1, /* TSF value at the start of rx */ ++ S_RXTSFTMRVAL_WD0, /* TSF value at the start of rx */ ++ S_RXSSN, /* Received start seq number for A-MPDU BA */ ++ S_RXQOSFLD, /* Rx-QoS field (if present) */ ++ ++ /* offset 0x21: Scratch pad regs used in microcode as temp storage */ ++ S_TMP0, /* stmp0 */ ++ S_TMP1, /* stmp1 */ ++ S_TMP2, /* stmp2 */ ++ S_TMP3, /* stmp3 */ ++ S_TMP4, /* stmp4 */ ++ S_TMP5, /* stmp5 */ ++ S_PRQPENALTY_CTR, /* Probe response queue penalty counter */ ++ S_ANTCNT, /* unsuccessful attempts on current ant. */ ++ S_SYMBOL, /* flag for possible symbol ctl frames */ ++ S_RXTP, /* rx frame type */ ++ S_STREG2, /* extra state storage */ ++ S_STREG3, /* even more extra state storage */ ++ S_STREG4, /* ... */ ++ S_STREG5, /* remember to initialize it to zero */ ++ ++ S_ADJPWR_IDX, ++ S_CUR_PTR, /* Temp pointer for A-MPDU re-Tx SHM table */ ++ S_REVID4, /* 0x33 */ ++ S_INDX, /* 0x34 */ ++ S_ADDR0, /* 0x35 */ ++ S_ADDR1, /* 0x36 */ ++ S_ADDR2, /* 0x37 */ ++ S_ADDR3, /* 0x38 */ ++ S_ADDR4, /* 0x39 */ ++ S_ADDR5, /* 0x3A */ ++ S_TMP6, /* 0x3B */ ++ S_KEYINDX_BU, /* Backup for Key index */ ++ S_MFGTEST_TMP0, /* Temp regs used for RX test calculations */ ++ S_RXESN, /* Received end sequence number for A-MPDU BA */ ++ S_STREG6, /* 0x3F */ ++}; ++ ++#define S_BEACON_INDX S_OLD_BREM ++#define S_PRS_INDX S_OLD_CWWIN ++#define S_PHYTYPE S_SSRC ++#define S_PHYVER S_SLRC ++ ++/* IHR SLOW_CTRL values */ ++#define SLOW_CTRL_PDE (1 << 0) ++#define SLOW_CTRL_FD (1 << 8) ++ ++/* ucode mac statistic counters in shared memory */ ++struct macstat { ++ u16 txallfrm; /* 0x80 */ ++ u16 txrtsfrm; /* 0x82 */ ++ u16 txctsfrm; /* 0x84 */ ++ u16 txackfrm; /* 0x86 */ ++ u16 txdnlfrm; /* 0x88 */ ++ u16 txbcnfrm; /* 0x8a */ ++ u16 txfunfl[8]; /* 0x8c - 0x9b */ ++ u16 txtplunfl; /* 0x9c */ ++ u16 txphyerr; /* 0x9e */ ++ u16 pktengrxducast; /* 0xa0 */ ++ u16 pktengrxdmcast; /* 0xa2 */ ++ u16 rxfrmtoolong; /* 0xa4 */ ++ u16 rxfrmtooshrt; /* 0xa6 */ ++ u16 rxinvmachdr; /* 0xa8 */ ++ u16 rxbadfcs; /* 0xaa */ ++ u16 rxbadplcp; /* 0xac */ ++ u16 rxcrsglitch; /* 0xae */ ++ u16 rxstrt; /* 0xb0 */ ++ u16 rxdfrmucastmbss; /* 0xb2 */ ++ u16 rxmfrmucastmbss; /* 0xb4 */ ++ u16 rxcfrmucast; /* 0xb6 */ ++ u16 rxrtsucast; /* 0xb8 */ ++ u16 rxctsucast; /* 0xba */ ++ u16 rxackucast; /* 0xbc */ ++ u16 rxdfrmocast; /* 0xbe */ ++ u16 rxmfrmocast; /* 0xc0 */ ++ u16 rxcfrmocast; /* 0xc2 */ ++ u16 rxrtsocast; /* 0xc4 */ ++ u16 rxctsocast; /* 0xc6 */ ++ u16 rxdfrmmcast; /* 0xc8 */ ++ u16 rxmfrmmcast; /* 0xca */ ++ u16 rxcfrmmcast; /* 0xcc */ ++ u16 rxbeaconmbss; /* 0xce */ ++ u16 rxdfrmucastobss; /* 0xd0 */ ++ u16 rxbeaconobss; /* 0xd2 */ ++ u16 rxrsptmout; /* 0xd4 */ ++ u16 bcntxcancl; /* 0xd6 */ ++ u16 PAD; ++ u16 rxf0ovfl; /* 0xda */ ++ u16 rxf1ovfl; /* 0xdc */ ++ u16 rxf2ovfl; /* 0xde */ ++ u16 txsfovfl; /* 0xe0 */ ++ u16 pmqovfl; /* 0xe2 */ ++ u16 rxcgprqfrm; /* 0xe4 */ ++ u16 rxcgprsqovfl; /* 0xe6 */ ++ u16 txcgprsfail; /* 0xe8 */ ++ u16 txcgprssuc; /* 0xea */ ++ u16 prs_timeout; /* 0xec */ ++ u16 rxnack; ++ u16 frmscons; ++ u16 txnack; ++ u16 txglitch_nack; ++ u16 txburst; /* 0xf6 # tx bursts */ ++ u16 bphy_rxcrsglitch; /* bphy rx crs glitch */ ++ u16 phywatchdog; /* 0xfa # of phy watchdog events */ ++ u16 PAD; ++ u16 bphy_badplcp; /* bphy bad plcp */ ++}; ++ ++/* dot11 core-specific control flags */ ++#define SICF_PCLKE 0x0004 /* PHY clock enable */ ++#define SICF_PRST 0x0008 /* PHY reset */ ++#define SICF_MPCLKE 0x0010 /* MAC PHY clockcontrol enable */ ++#define SICF_FREF 0x0020 /* PLL FreqRefSelect */ ++/* NOTE: the following bw bits only apply when the core is attached ++ * to a NPHY ++ */ ++#define SICF_BWMASK 0x00c0 /* phy clock mask (b6 & b7) */ ++#define SICF_BW40 0x0080 /* 40MHz BW (160MHz phyclk) */ ++#define SICF_BW20 0x0040 /* 20MHz BW (80MHz phyclk) */ ++#define SICF_BW10 0x0000 /* 10MHz BW (40MHz phyclk) */ ++#define SICF_GMODE 0x2000 /* gmode enable */ ++ ++/* dot11 core-specific status flags */ ++#define SISF_2G_PHY 0x0001 /* 2.4G capable phy */ ++#define SISF_5G_PHY 0x0002 /* 5G capable phy */ ++#define SISF_FCLKA 0x0004 /* FastClkAvailable */ ++#define SISF_DB_PHY 0x0008 /* Dualband phy */ ++ ++/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg === */ ++/* radio and LPPHY regs are separated */ ++ ++#define BPHY_REG_OFT_BASE 0x0 ++/* offsets for indirect access to bphy registers */ ++#define BPHY_BB_CONFIG 0x01 ++#define BPHY_ADCBIAS 0x02 ++#define BPHY_ANACORE 0x03 ++#define BPHY_PHYCRSTH 0x06 ++#define BPHY_TEST 0x0a ++#define BPHY_PA_TX_TO 0x10 ++#define BPHY_SYNTH_DC_TO 0x11 ++#define BPHY_PA_TX_TIME_UP 0x12 ++#define BPHY_RX_FLTR_TIME_UP 0x13 ++#define BPHY_TX_POWER_OVERRIDE 0x14 ++#define BPHY_RF_OVERRIDE 0x15 ++#define BPHY_RF_TR_LOOKUP1 0x16 ++#define BPHY_RF_TR_LOOKUP2 0x17 ++#define BPHY_COEFFS 0x18 ++#define BPHY_PLL_OUT 0x19 ++#define BPHY_REFRESH_MAIN 0x1a ++#define BPHY_REFRESH_TO0 0x1b ++#define BPHY_REFRESH_TO1 0x1c ++#define BPHY_RSSI_TRESH 0x20 ++#define BPHY_IQ_TRESH_HH 0x21 ++#define BPHY_IQ_TRESH_H 0x22 ++#define BPHY_IQ_TRESH_L 0x23 ++#define BPHY_IQ_TRESH_LL 0x24 ++#define BPHY_GAIN 0x25 ++#define BPHY_LNA_GAIN_RANGE 0x26 ++#define BPHY_JSSI 0x27 ++#define BPHY_TSSI_CTL 0x28 ++#define BPHY_TSSI 0x29 ++#define BPHY_TR_LOSS_CTL 0x2a ++#define BPHY_LO_LEAKAGE 0x2b ++#define BPHY_LO_RSSI_ACC 0x2c ++#define BPHY_LO_IQMAG_ACC 0x2d ++#define BPHY_TX_DC_OFF1 0x2e ++#define BPHY_TX_DC_OFF2 0x2f ++#define BPHY_PEAK_CNT_THRESH 0x30 ++#define BPHY_FREQ_OFFSET 0x31 ++#define BPHY_DIVERSITY_CTL 0x32 ++#define BPHY_PEAK_ENERGY_LO 0x33 ++#define BPHY_PEAK_ENERGY_HI 0x34 ++#define BPHY_SYNC_CTL 0x35 ++#define BPHY_TX_PWR_CTRL 0x36 ++#define BPHY_TX_EST_PWR 0x37 ++#define BPHY_STEP 0x38 ++#define BPHY_WARMUP 0x39 ++#define BPHY_LMS_CFF_READ 0x3a ++#define BPHY_LMS_COEFF_I 0x3b ++#define BPHY_LMS_COEFF_Q 0x3c ++#define BPHY_SIG_POW 0x3d ++#define BPHY_RFDC_CANCEL_CTL 0x3e ++#define BPHY_HDR_TYPE 0x40 ++#define BPHY_SFD_TO 0x41 ++#define BPHY_SFD_CTL 0x42 ++#define BPHY_DEBUG 0x43 ++#define BPHY_RX_DELAY_COMP 0x44 ++#define BPHY_CRS_DROP_TO 0x45 ++#define BPHY_SHORT_SFD_NZEROS 0x46 ++#define BPHY_DSSS_COEFF1 0x48 ++#define BPHY_DSSS_COEFF2 0x49 ++#define BPHY_CCK_COEFF1 0x4a ++#define BPHY_CCK_COEFF2 0x4b ++#define BPHY_TR_CORR 0x4c ++#define BPHY_ANGLE_SCALE 0x4d ++#define BPHY_TX_PWR_BASE_IDX 0x4e ++#define BPHY_OPTIONAL_MODES2 0x4f ++#define BPHY_CCK_LMS_STEP 0x50 ++#define BPHY_BYPASS 0x51 ++#define BPHY_CCK_DELAY_LONG 0x52 ++#define BPHY_CCK_DELAY_SHORT 0x53 ++#define BPHY_PPROC_CHAN_DELAY 0x54 ++#define BPHY_DDFS_ENABLE 0x58 ++#define BPHY_PHASE_SCALE 0x59 ++#define BPHY_FREQ_CONTROL 0x5a ++#define BPHY_LNA_GAIN_RANGE_10 0x5b ++#define BPHY_LNA_GAIN_RANGE_32 0x5c ++#define BPHY_OPTIONAL_MODES 0x5d ++#define BPHY_RX_STATUS2 0x5e ++#define BPHY_RX_STATUS3 0x5f ++#define BPHY_DAC_CONTROL 0x60 ++#define BPHY_ANA11G_FILT_CTRL 0x62 ++#define BPHY_REFRESH_CTRL 0x64 ++#define BPHY_RF_OVERRIDE2 0x65 ++#define BPHY_SPUR_CANCEL_CTRL 0x66 ++#define BPHY_FINE_DIGIGAIN_CTRL 0x67 ++#define BPHY_RSSI_LUT 0x88 ++#define BPHY_RSSI_LUT_END 0xa7 ++#define BPHY_TSSI_LUT 0xa8 ++#define BPHY_TSSI_LUT_END 0xc7 ++#define BPHY_TSSI2PWR_LUT 0x380 ++#define BPHY_TSSI2PWR_LUT_END 0x39f ++#define BPHY_LOCOMP_LUT 0x3a0 ++#define BPHY_LOCOMP_LUT_END 0x3bf ++#define BPHY_TXGAIN_LUT 0x3c0 ++#define BPHY_TXGAIN_LUT_END 0x3ff ++ ++/* Bits in BB_CONFIG: */ ++#define PHY_BBC_ANT_MASK 0x0180 ++#define PHY_BBC_ANT_SHIFT 7 ++#define BB_DARWIN 0x1000 ++#define BBCFG_RESETCCA 0x4000 ++#define BBCFG_RESETRX 0x8000 ++ ++/* Bits in phytest(0x0a): */ ++#define TST_DDFS 0x2000 ++#define TST_TXFILT1 0x0800 ++#define TST_UNSCRAM 0x0400 ++#define TST_CARR_SUPP 0x0200 ++#define TST_DC_COMP_LOOP 0x0100 ++#define TST_LOOPBACK 0x0080 ++#define TST_TXFILT0 0x0040 ++#define TST_TXTEST_ENABLE 0x0020 ++#define TST_TXTEST_RATE 0x0018 ++#define TST_TXTEST_PHASE 0x0007 ++ ++/* phytest txTestRate values */ ++#define TST_TXTEST_RATE_1MBPS 0 ++#define TST_TXTEST_RATE_2MBPS 1 ++#define TST_TXTEST_RATE_5_5MBPS 2 ++#define TST_TXTEST_RATE_11MBPS 3 ++#define TST_TXTEST_RATE_SHIFT 3 ++ ++#define SHM_BYT_CNT 0x2 /* IHR location */ ++#define MAX_BYT_CNT 0x600 /* Maximum frame len */ ++ ++struct d11cnt { ++ u32 txfrag; ++ u32 txmulti; ++ u32 txfail; ++ u32 txretry; ++ u32 txretrie; ++ u32 rxdup; ++ u32 txrts; ++ u32 txnocts; ++ u32 txnoack; ++ u32 rxfrag; ++ u32 rxmulti; ++ u32 rxcrc; ++ u32 txfrmsnt; ++ u32 rxundec; ++}; ++ ++#endif /* _BRCM_D11_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.c.orig 2011-11-09 13:46:58.244800645 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.c 2011-11-09 13:47:16.997566205 -0500 +@@ -0,0 +1,1425 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "types.h" ++#include "dma.h" ++ ++/* ++ * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within ++ * a contiguous 8kB physical address. ++ */ ++#define D64RINGALIGN_BITS 13 ++#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) ++#define D64RINGALIGN (1 << D64RINGALIGN_BITS) ++ ++#define D64MAXDD (D64MAXRINGSZ / sizeof(struct dma64desc)) ++ ++/* transmit channel control */ ++#define D64_XC_XE 0x00000001 /* transmit enable */ ++#define D64_XC_SE 0x00000002 /* transmit suspend request */ ++#define D64_XC_LE 0x00000004 /* loopback enable */ ++#define D64_XC_FL 0x00000010 /* flush request */ ++#define D64_XC_PD 0x00000800 /* parity check disable */ ++#define D64_XC_AE 0x00030000 /* address extension bits */ ++#define D64_XC_AE_SHIFT 16 ++ ++/* transmit descriptor table pointer */ ++#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */ ++ ++/* transmit channel status */ ++#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ ++#define D64_XS0_XS_SHIFT 28 ++#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ ++#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ ++#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ ++#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ ++#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */ ++#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ ++#define D64_XS1_XE_SHIFT 28 ++#define D64_XS1_XE_NOERR 0x00000000 /* no error */ ++#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ ++#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ ++#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ ++#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_XS1_XE_COREE 0x50000000 /* core error */ ++ ++/* receive channel control */ ++/* receive enable */ ++#define D64_RC_RE 0x00000001 ++/* receive frame offset */ ++#define D64_RC_RO_MASK 0x000000fe ++#define D64_RC_RO_SHIFT 1 ++/* direct fifo receive (pio) mode */ ++#define D64_RC_FM 0x00000100 ++/* separate rx header descriptor enable */ ++#define D64_RC_SH 0x00000200 ++/* overflow continue */ ++#define D64_RC_OC 0x00000400 ++/* parity check disable */ ++#define D64_RC_PD 0x00000800 ++/* address extension bits */ ++#define D64_RC_AE 0x00030000 ++#define D64_RC_AE_SHIFT 16 ++ ++/* flags for dma controller */ ++/* partity enable */ ++#define DMA_CTRL_PEN (1 << 0) ++/* rx overflow continue */ ++#define DMA_CTRL_ROC (1 << 1) ++/* allow rx scatter to multiple descriptors */ ++#define DMA_CTRL_RXMULTI (1 << 2) ++/* Unframed Rx/Tx data */ ++#define DMA_CTRL_UNFRAMED (1 << 3) ++ ++/* receive descriptor table pointer */ ++#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */ ++ ++/* receive channel status */ ++#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ ++#define D64_RS0_RS_SHIFT 28 ++#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ ++#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ ++#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ ++#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ ++#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ ++#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ ++#define D64_RS1_RE_SHIFT 28 ++#define D64_RS1_RE_NOERR 0x00000000 /* no error */ ++#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ ++#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ ++#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ ++#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_RS1_RE_COREE 0x50000000 /* core error */ ++ ++/* fifoaddr */ ++#define D64_FA_OFF_MASK 0xffff /* offset */ ++#define D64_FA_SEL_MASK 0xf0000 /* select */ ++#define D64_FA_SEL_SHIFT 16 ++#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ ++#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ ++#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ ++#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ ++#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ ++#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ ++#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ ++#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ ++#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ ++#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ ++ ++/* descriptor control flags 1 */ ++#define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */ ++#define D64_CTRL1_EOT ((u32)1 << 28) /* end of descriptor table */ ++#define D64_CTRL1_IOC ((u32)1 << 29) /* interrupt on completion */ ++#define D64_CTRL1_EOF ((u32)1 << 30) /* end of frame */ ++#define D64_CTRL1_SOF ((u32)1 << 31) /* start of frame */ ++ ++/* descriptor control flags 2 */ ++/* buffer byte count. real data len must <= 16KB */ ++#define D64_CTRL2_BC_MASK 0x00007fff ++/* address extension bits */ ++#define D64_CTRL2_AE 0x00030000 ++#define D64_CTRL2_AE_SHIFT 16 ++/* parity bit */ ++#define D64_CTRL2_PARITY 0x00040000 ++ ++/* control flags in the range [27:20] are core-specific and not defined here */ ++#define D64_CTRL_CORE_MASK 0x0ff00000 ++ ++#define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */ ++#define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */ ++#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */ ++#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ ++ ++/* ++ * packet headroom necessary to accommodate the largest header ++ * in the system, (i.e TXOFF). By doing, we avoid the need to ++ * allocate an extra buffer for the header when bridging to WL. ++ * There is a compile time check in wlc.c which ensure that this ++ * value is at least as big as TXOFF. This value is used in ++ * dma_rxfill(). ++ */ ++ ++#define BCMEXTRAHDROOM 172 ++ ++/* debug/trace */ ++#ifdef BCMDBG ++#define DMA_ERROR(args) \ ++ do { \ ++ if (!(*di->msg_level & 1)) \ ++ ; \ ++ else \ ++ printk args; \ ++ } while (0) ++#define DMA_TRACE(args) \ ++ do { \ ++ if (!(*di->msg_level & 2)) \ ++ ; \ ++ else \ ++ printk args; \ ++ } while (0) ++#else ++#define DMA_ERROR(args) ++#define DMA_TRACE(args) ++#endif /* BCMDBG */ ++ ++#define DMA_NONE(args) ++ ++#define MAXNAMEL 8 /* 8 char names */ ++ ++/* macros to convert between byte offsets and indexes */ ++#define B2I(bytes, type) ((bytes) / sizeof(type)) ++#define I2B(index, type) ((index) * sizeof(type)) ++ ++#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */ ++#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */ ++ ++#define PCI64ADDR_HIGH 0x80000000 /* address[63] */ ++#define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */ ++ ++/* ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++struct dma64desc { ++ __le32 ctrl1; /* misc control bits & bufcount */ ++ __le32 ctrl2; /* buffer count and address extension */ ++ __le32 addrlow; /* memory address of the date buffer, bits 31:0 */ ++ __le32 addrhigh; /* memory address of the date buffer, bits 63:32 */ ++}; ++ ++/* dma engine software state */ ++struct dma_info { ++ struct dma_pub dma; /* exported structure */ ++ uint *msg_level; /* message level pointer */ ++ char name[MAXNAMEL]; /* callers name for diag msgs */ ++ ++ struct pci_dev *pbus; /* bus handle */ ++ ++ bool dma64; /* this dma engine is operating in 64-bit mode */ ++ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ ++ ++ /* 64-bit dma tx engine registers */ ++ struct dma64regs __iomem *d64txregs; ++ /* 64-bit dma rx engine registers */ ++ struct dma64regs __iomem *d64rxregs; ++ /* pointer to dma64 tx descriptor ring */ ++ struct dma64desc *txd64; ++ /* pointer to dma64 rx descriptor ring */ ++ struct dma64desc *rxd64; ++ ++ u16 dmadesc_align; /* alignment requirement for dma descriptors */ ++ ++ u16 ntxd; /* # tx descriptors tunable */ ++ u16 txin; /* index of next descriptor to reclaim */ ++ u16 txout; /* index of next descriptor to post */ ++ /* pointer to parallel array of pointers to packets */ ++ struct sk_buff **txp; ++ /* Aligned physical address of descriptor ring */ ++ dma_addr_t txdpa; ++ /* Original physical address of descriptor ring */ ++ dma_addr_t txdpaorig; ++ u16 txdalign; /* #bytes added to alloc'd mem to align txd */ ++ u32 txdalloc; /* #bytes allocated for the ring */ ++ u32 xmtptrbase; /* When using unaligned descriptors, the ptr register ++ * is not just an index, it needs all 13 bits to be ++ * an offset from the addr register. ++ */ ++ ++ u16 nrxd; /* # rx descriptors tunable */ ++ u16 rxin; /* index of next descriptor to reclaim */ ++ u16 rxout; /* index of next descriptor to post */ ++ /* pointer to parallel array of pointers to packets */ ++ struct sk_buff **rxp; ++ /* Aligned physical address of descriptor ring */ ++ dma_addr_t rxdpa; ++ /* Original physical address of descriptor ring */ ++ dma_addr_t rxdpaorig; ++ u16 rxdalign; /* #bytes added to alloc'd mem to align rxd */ ++ u32 rxdalloc; /* #bytes allocated for the ring */ ++ u32 rcvptrbase; /* Base for ptr reg when using unaligned descriptors */ ++ ++ /* tunables */ ++ unsigned int rxbufsize; /* rx buffer size in bytes, not including ++ * the extra headroom ++ */ ++ uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper ++ * stack, e.g. some rx pkt buffers will be ++ * bridged to tx side without byte copying. ++ * The extra headroom needs to be large enough ++ * to fit txheader needs. Some dongle driver may ++ * not need it. ++ */ ++ uint nrxpost; /* # rx buffers to keep posted */ ++ unsigned int rxoffset; /* rxcontrol offset */ ++ /* add to get dma address of descriptor ring, low 32 bits */ ++ uint ddoffsetlow; ++ /* high 32 bits */ ++ uint ddoffsethigh; ++ /* add to get dma address of data buffer, low 32 bits */ ++ uint dataoffsetlow; ++ /* high 32 bits */ ++ uint dataoffsethigh; ++ /* descriptor base need to be aligned or not */ ++ bool aligndesc_4k; ++}; ++ ++/* ++ * default dma message level (if input msg_level ++ * pointer is null in dma_attach()) ++ */ ++static uint dma_msg_level; ++ ++/* Check for odd number of 1's */ ++static u32 parity32(__le32 data) ++{ ++ /* no swap needed for counting 1's */ ++ u32 par_data = *(u32 *)&data; ++ ++ par_data ^= par_data >> 16; ++ par_data ^= par_data >> 8; ++ par_data ^= par_data >> 4; ++ par_data ^= par_data >> 2; ++ par_data ^= par_data >> 1; ++ ++ return par_data & 1; ++} ++ ++static bool dma64_dd_parity(struct dma64desc *dd) ++{ ++ return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2); ++} ++ ++/* descriptor bumping functions */ ++ ++static uint xxd(uint x, uint n) ++{ ++ return x & (n - 1); /* faster than %, but n must be power of 2 */ ++} ++ ++static uint txd(struct dma_info *di, uint x) ++{ ++ return xxd(x, di->ntxd); ++} ++ ++static uint rxd(struct dma_info *di, uint x) ++{ ++ return xxd(x, di->nrxd); ++} ++ ++static uint nexttxd(struct dma_info *di, uint i) ++{ ++ return txd(di, i + 1); ++} ++ ++static uint prevtxd(struct dma_info *di, uint i) ++{ ++ return txd(di, i - 1); ++} ++ ++static uint nextrxd(struct dma_info *di, uint i) ++{ ++ return txd(di, i + 1); ++} ++ ++static uint ntxdactive(struct dma_info *di, uint h, uint t) ++{ ++ return txd(di, t-h); ++} ++ ++static uint nrxdactive(struct dma_info *di, uint h, uint t) ++{ ++ return rxd(di, t-h); ++} ++ ++static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) ++{ ++ uint dmactrlflags = di->dma.dmactrlflags; ++ ++ if (di == NULL) { ++ DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name)); ++ return 0; ++ } ++ ++ dmactrlflags &= ~mask; ++ dmactrlflags |= flags; ++ ++ /* If trying to enable parity, check if parity is actually supported */ ++ if (dmactrlflags & DMA_CTRL_PEN) { ++ u32 control; ++ ++ control = R_REG(&di->d64txregs->control); ++ W_REG(&di->d64txregs->control, ++ control | D64_XC_PD); ++ if (R_REG(&di->d64txregs->control) & D64_XC_PD) ++ /* We *can* disable it so it is supported, ++ * restore control register ++ */ ++ W_REG(&di->d64txregs->control, ++ control); ++ else ++ /* Not supported, don't allow it to be enabled */ ++ dmactrlflags &= ~DMA_CTRL_PEN; ++ } ++ ++ di->dma.dmactrlflags = dmactrlflags; ++ ++ return dmactrlflags; ++} ++ ++static bool _dma64_addrext(struct dma64regs __iomem *dma64regs) ++{ ++ u32 w; ++ OR_REG(&dma64regs->control, D64_XC_AE); ++ w = R_REG(&dma64regs->control); ++ AND_REG(&dma64regs->control, ~D64_XC_AE); ++ return (w & D64_XC_AE) == D64_XC_AE; ++} ++ ++/* ++ * return true if this dma engine supports DmaExtendedAddrChanges, ++ * otherwise false ++ */ ++static bool _dma_isaddrext(struct dma_info *di) ++{ ++ /* DMA64 supports full 32- or 64-bit operation. AE is always valid */ ++ ++ /* not all tx or rx channel are available */ ++ if (di->d64txregs != NULL) { ++ if (!_dma64_addrext(di->d64txregs)) ++ DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have " ++ "AE set\n", di->name)); ++ return true; ++ } else if (di->d64rxregs != NULL) { ++ if (!_dma64_addrext(di->d64rxregs)) ++ DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have " ++ "AE set\n", di->name)); ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool _dma_descriptor_align(struct dma_info *di) ++{ ++ u32 addrl; ++ ++ /* Check to see if the descriptors need to be aligned on 4K/8K or not */ ++ if (di->d64txregs != NULL) { ++ W_REG(&di->d64txregs->addrlow, 0xff0); ++ addrl = R_REG(&di->d64txregs->addrlow); ++ if (addrl != 0) ++ return false; ++ } else if (di->d64rxregs != NULL) { ++ W_REG(&di->d64rxregs->addrlow, 0xff0); ++ addrl = R_REG(&di->d64rxregs->addrlow); ++ if (addrl != 0) ++ return false; ++ } ++ return true; ++} ++ ++/* ++ * Descriptor table must start at the DMA hardware dictated alignment, so ++ * allocated memory must be large enough to support this requirement. ++ */ ++static void *dma_alloc_consistent(struct pci_dev *pdev, uint size, ++ u16 align_bits, uint *alloced, ++ dma_addr_t *pap) ++{ ++ if (align_bits) { ++ u16 align = (1 << align_bits); ++ if (!IS_ALIGNED(PAGE_SIZE, align)) ++ size += align; ++ *alloced = size; ++ } ++ return pci_alloc_consistent(pdev, size, pap); ++} ++ ++static ++u8 dma_align_sizetobits(uint size) ++{ ++ u8 bitpos = 0; ++ while (size >>= 1) ++ bitpos++; ++ return bitpos; ++} ++ ++/* This function ensures that the DMA descriptor ring will not get allocated ++ * across Page boundary. If the allocation is done across the page boundary ++ * at the first time, then it is freed and the allocation is done at ++ * descriptor ring size aligned location. This will ensure that the ring will ++ * not cross page boundary ++ */ ++static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size, ++ u16 *alignbits, uint *alloced, ++ dma_addr_t *descpa) ++{ ++ void *va; ++ u32 desc_strtaddr; ++ u32 alignbytes = 1 << *alignbits; ++ ++ va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa); ++ ++ if (NULL == va) ++ return NULL; ++ ++ desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes); ++ if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr ++ & boundary)) { ++ *alignbits = dma_align_sizetobits(size); ++ pci_free_consistent(di->pbus, size, va, *descpa); ++ va = dma_alloc_consistent(di->pbus, size, *alignbits, ++ alloced, descpa); ++ } ++ return va; ++} ++ ++static bool dma64_alloc(struct dma_info *di, uint direction) ++{ ++ u16 size; ++ uint ddlen; ++ void *va; ++ uint alloced = 0; ++ u16 align; ++ u16 align_bits; ++ ++ ddlen = sizeof(struct dma64desc); ++ ++ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen); ++ align_bits = di->dmadesc_align; ++ align = (1 << align_bits); ++ ++ if (direction == DMA_TX) { ++ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, ++ &alloced, &di->txdpaorig); ++ if (va == NULL) { ++ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(ntxd)" ++ " failed\n", di->name)); ++ return false; ++ } ++ align = (1 << align_bits); ++ di->txd64 = (struct dma64desc *) ++ roundup((unsigned long)va, align); ++ di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va); ++ di->txdpa = di->txdpaorig + di->txdalign; ++ di->txdalloc = alloced; ++ } else { ++ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, ++ &alloced, &di->rxdpaorig); ++ if (va == NULL) { ++ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(nrxd)" ++ " failed\n", di->name)); ++ return false; ++ } ++ align = (1 << align_bits); ++ di->rxd64 = (struct dma64desc *) ++ roundup((unsigned long)va, align); ++ di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va); ++ di->rxdpa = di->rxdpaorig + di->rxdalign; ++ di->rxdalloc = alloced; ++ } ++ ++ return true; ++} ++ ++static bool _dma_alloc(struct dma_info *di, uint direction) ++{ ++ return dma64_alloc(di, direction); ++} ++ ++struct dma_pub *dma_attach(char *name, struct si_pub *sih, ++ void __iomem *dmaregstx, void __iomem *dmaregsrx, ++ uint ntxd, uint nrxd, ++ uint rxbufsize, int rxextheadroom, ++ uint nrxpost, uint rxoffset, uint *msg_level) ++{ ++ struct dma_info *di; ++ uint size; ++ ++ /* allocate private info structure */ ++ di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); ++ if (di == NULL) ++ return NULL; ++ ++ di->msg_level = msg_level ? msg_level : &dma_msg_level; ++ ++ ++ di->dma64 = ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64); ++ ++ /* init dma reg pointer */ ++ di->d64txregs = (struct dma64regs __iomem *) dmaregstx; ++ di->d64rxregs = (struct dma64regs __iomem *) dmaregsrx; ++ ++ /* ++ * Default flags (which can be changed by the driver calling ++ * dma_ctrlflags before enable): For backwards compatibility ++ * both Rx Overflow Continue and Parity are DISABLED. ++ */ ++ _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0); ++ ++ DMA_TRACE(("%s: dma_attach: %s flags 0x%x ntxd %d nrxd %d " ++ "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d " ++ "dmaregstx %p dmaregsrx %p\n", name, "DMA64", ++ di->dma.dmactrlflags, ntxd, nrxd, rxbufsize, ++ rxextheadroom, nrxpost, rxoffset, dmaregstx, dmaregsrx)); ++ ++ /* make a private copy of our callers name */ ++ strncpy(di->name, name, MAXNAMEL); ++ di->name[MAXNAMEL - 1] = '\0'; ++ ++ di->pbus = ((struct si_info *)sih)->pbus; ++ ++ /* save tunables */ ++ di->ntxd = (u16) ntxd; ++ di->nrxd = (u16) nrxd; ++ ++ /* the actual dma size doesn't include the extra headroom */ ++ di->rxextrahdrroom = ++ (rxextheadroom == -1) ? BCMEXTRAHDROOM : rxextheadroom; ++ if (rxbufsize > BCMEXTRAHDROOM) ++ di->rxbufsize = (u16) (rxbufsize - di->rxextrahdrroom); ++ else ++ di->rxbufsize = (u16) rxbufsize; ++ ++ di->nrxpost = (u16) nrxpost; ++ di->rxoffset = (u8) rxoffset; ++ ++ /* ++ * figure out the DMA physical address offset for dd and data ++ * PCI/PCIE: they map silicon backplace address to zero ++ * based memory, need offset ++ * Other bus: use zero SI_BUS BIGENDIAN kludge: use sdram ++ * swapped region for data buffer, not descriptor ++ */ ++ di->ddoffsetlow = 0; ++ di->dataoffsetlow = 0; ++ /* add offset for pcie with DMA64 bus */ ++ di->ddoffsetlow = 0; ++ di->ddoffsethigh = SI_PCIE_DMA_H32; ++ di->dataoffsetlow = di->ddoffsetlow; ++ di->dataoffsethigh = di->ddoffsethigh; ++ /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ ++ if ((ai_coreid(sih) == SDIOD_CORE_ID) ++ && ((ai_corerev(sih) > 0) && (ai_corerev(sih) <= 2))) ++ di->addrext = 0; ++ else if ((ai_coreid(sih) == I2S_CORE_ID) && ++ ((ai_corerev(sih) == 0) || (ai_corerev(sih) == 1))) ++ di->addrext = 0; ++ else ++ di->addrext = _dma_isaddrext(di); ++ ++ /* does the descriptor need to be aligned and if yes, on 4K/8K or not */ ++ di->aligndesc_4k = _dma_descriptor_align(di); ++ if (di->aligndesc_4k) { ++ di->dmadesc_align = D64RINGALIGN_BITS; ++ if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2)) ++ /* for smaller dd table, HW relax alignment reqmnt */ ++ di->dmadesc_align = D64RINGALIGN_BITS - 1; ++ } else { ++ di->dmadesc_align = 4; /* 16 byte alignment */ ++ } ++ ++ DMA_NONE(("DMA descriptor align_needed %d, align %d\n", ++ di->aligndesc_4k, di->dmadesc_align)); ++ ++ /* allocate tx packet pointer vector */ ++ if (ntxd) { ++ size = ntxd * sizeof(void *); ++ di->txp = kzalloc(size, GFP_ATOMIC); ++ if (di->txp == NULL) ++ goto fail; ++ } ++ ++ /* allocate rx packet pointer vector */ ++ if (nrxd) { ++ size = nrxd * sizeof(void *); ++ di->rxp = kzalloc(size, GFP_ATOMIC); ++ if (di->rxp == NULL) ++ goto fail; ++ } ++ ++ /* ++ * allocate transmit descriptor ring, only need ntxd descriptors ++ * but it must be aligned ++ */ ++ if (ntxd) { ++ if (!_dma_alloc(di, DMA_TX)) ++ goto fail; ++ } ++ ++ /* ++ * allocate receive descriptor ring, only need nrxd descriptors ++ * but it must be aligned ++ */ ++ if (nrxd) { ++ if (!_dma_alloc(di, DMA_RX)) ++ goto fail; ++ } ++ ++ if ((di->ddoffsetlow != 0) && !di->addrext) { ++ if (di->txdpa > SI_PCI_DMA_SZ) { ++ DMA_ERROR(("%s: dma_attach: txdpa 0x%x: addrext not " ++ "supported\n", di->name, (u32)di->txdpa)); ++ goto fail; ++ } ++ if (di->rxdpa > SI_PCI_DMA_SZ) { ++ DMA_ERROR(("%s: dma_attach: rxdpa 0x%x: addrext not " ++ "supported\n", di->name, (u32)di->rxdpa)); ++ goto fail; ++ } ++ } ++ ++ DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x " ++ "dataoffsethigh " "0x%x addrext %d\n", di->ddoffsetlow, ++ di->ddoffsethigh, di->dataoffsetlow, di->dataoffsethigh, ++ di->addrext)); ++ ++ return (struct dma_pub *) di; ++ ++ fail: ++ dma_detach((struct dma_pub *)di); ++ return NULL; ++} ++ ++static inline void ++dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring, ++ dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount) ++{ ++ u32 ctrl2 = bufcount & D64_CTRL2_BC_MASK; ++ ++ /* PCI bus with big(>1G) physical address, use address extension */ ++ if ((di->dataoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) { ++ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow); ++ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh); ++ ddring[outidx].ctrl1 = cpu_to_le32(*flags); ++ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2); ++ } else { ++ /* address extension for 32-bit PCI */ ++ u32 ae; ++ ++ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; ++ pa &= ~PCI32ADDR_HIGH; ++ ++ ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE; ++ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow); ++ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh); ++ ddring[outidx].ctrl1 = cpu_to_le32(*flags); ++ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2); ++ } ++ if (di->dma.dmactrlflags & DMA_CTRL_PEN) { ++ if (dma64_dd_parity(&ddring[outidx])) ++ ddring[outidx].ctrl2 = ++ cpu_to_le32(ctrl2 | D64_CTRL2_PARITY); ++ } ++} ++ ++/* !! may be called with core in reset */ ++void dma_detach(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ DMA_TRACE(("%s: dma_detach\n", di->name)); ++ ++ /* free dma descriptor rings */ ++ if (di->txd64) ++ pci_free_consistent(di->pbus, di->txdalloc, ++ ((s8 *)di->txd64 - di->txdalign), ++ (di->txdpaorig)); ++ if (di->rxd64) ++ pci_free_consistent(di->pbus, di->rxdalloc, ++ ((s8 *)di->rxd64 - di->rxdalign), ++ (di->rxdpaorig)); ++ ++ /* free packet pointer vectors */ ++ kfree(di->txp); ++ kfree(di->rxp); ++ ++ /* free our private info structure */ ++ kfree(di); ++ ++} ++ ++/* initialize descriptor table base address */ ++static void ++_dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa) ++{ ++ if (!di->aligndesc_4k) { ++ if (direction == DMA_TX) ++ di->xmtptrbase = pa; ++ else ++ di->rcvptrbase = pa; ++ } ++ ++ if ((di->ddoffsetlow == 0) ++ || !(pa & PCI32ADDR_HIGH)) { ++ if (direction == DMA_TX) { ++ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); ++ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); ++ } else { ++ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); ++ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); ++ } ++ } else { ++ /* DMA64 32bits address extension */ ++ u32 ae; ++ ++ /* shift the high bit(s) from pa to ae */ ++ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; ++ pa &= ~PCI32ADDR_HIGH; ++ ++ if (direction == DMA_TX) { ++ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); ++ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); ++ SET_REG(&di->d64txregs->control, ++ D64_XC_AE, (ae << D64_XC_AE_SHIFT)); ++ } else { ++ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); ++ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); ++ SET_REG(&di->d64rxregs->control, ++ D64_RC_AE, (ae << D64_RC_AE_SHIFT)); ++ } ++ } ++} ++ ++static void _dma_rxenable(struct dma_info *di) ++{ ++ uint dmactrlflags = di->dma.dmactrlflags; ++ u32 control; ++ ++ DMA_TRACE(("%s: dma_rxenable\n", di->name)); ++ ++ control = ++ (R_REG(&di->d64rxregs->control) & D64_RC_AE) | ++ D64_RC_RE; ++ ++ if ((dmactrlflags & DMA_CTRL_PEN) == 0) ++ control |= D64_RC_PD; ++ ++ if (dmactrlflags & DMA_CTRL_ROC) ++ control |= D64_RC_OC; ++ ++ W_REG(&di->d64rxregs->control, ++ ((di->rxoffset << D64_RC_RO_SHIFT) | control)); ++} ++ ++void dma_rxinit(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ DMA_TRACE(("%s: dma_rxinit\n", di->name)); ++ ++ if (di->nrxd == 0) ++ return; ++ ++ di->rxin = di->rxout = 0; ++ ++ /* clear rx descriptor ring */ ++ memset(di->rxd64, '\0', di->nrxd * sizeof(struct dma64desc)); ++ ++ /* DMA engine with out alignment requirement requires table to be inited ++ * before enabling the engine ++ */ ++ if (!di->aligndesc_4k) ++ _dma_ddtable_init(di, DMA_RX, di->rxdpa); ++ ++ _dma_rxenable(di); ++ ++ if (di->aligndesc_4k) ++ _dma_ddtable_init(di, DMA_RX, di->rxdpa); ++} ++ ++static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall) ++{ ++ uint i, curr; ++ struct sk_buff *rxp; ++ dma_addr_t pa; ++ ++ i = di->rxin; ++ ++ /* return if no packets posted */ ++ if (i == di->rxout) ++ return NULL; ++ ++ curr = ++ B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) - ++ di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc); ++ ++ /* ignore curr if forceall */ ++ if (!forceall && (i == curr)) ++ return NULL; ++ ++ /* get the packet pointer that corresponds to the rx descriptor */ ++ rxp = di->rxp[i]; ++ di->rxp[i] = NULL; ++ ++ pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow; ++ ++ /* clear this packet from the descriptor ring */ ++ pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE); ++ ++ di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef); ++ di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef); ++ ++ di->rxin = nextrxd(di, i); ++ ++ return rxp; ++} ++ ++static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) ++{ ++ if (di->nrxd == 0) ++ return NULL; ++ ++ return dma64_getnextrxp(di, forceall); ++} ++ ++/* ++ * !! rx entry routine ++ * returns a pointer to the next frame received, or NULL if there are no more ++ * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is ++ * supported with pkts chain ++ * otherwise, it's treated as giant pkt and will be tossed. ++ * The DMA scattering starts with normal DMA header, followed by first ++ * buffer data. After it reaches the max size of buffer, the data continues ++ * in next DMA descriptor buffer WITHOUT DMA header ++ */ ++struct sk_buff *dma_rx(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ struct sk_buff *p, *head, *tail; ++ uint len; ++ uint pkt_len; ++ int resid = 0; ++ ++ next_frame: ++ head = _dma_getnextrxp(di, false); ++ if (head == NULL) ++ return NULL; ++ ++ len = le16_to_cpu(*(__le16 *) (head->data)); ++ DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); ++ dma_spin_for_len(len, head); ++ ++ /* set actual length */ ++ pkt_len = min((di->rxoffset + len), di->rxbufsize); ++ __skb_trim(head, pkt_len); ++ resid = len - (di->rxbufsize - di->rxoffset); ++ ++ /* check for single or multi-buffer rx */ ++ if (resid > 0) { ++ tail = head; ++ while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { ++ tail->next = p; ++ pkt_len = min_t(uint, resid, di->rxbufsize); ++ __skb_trim(p, pkt_len); ++ ++ tail = p; ++ resid -= di->rxbufsize; ++ } ++ ++#ifdef BCMDBG ++ if (resid > 0) { ++ uint cur; ++ cur = ++ B2I(((R_REG(&di->d64rxregs->status0) & ++ D64_RS0_CD_MASK) - ++ di->rcvptrbase) & D64_RS0_CD_MASK, ++ struct dma64desc); ++ DMA_ERROR(("dma_rx, rxin %d rxout %d, hw_curr %d\n", ++ di->rxin, di->rxout, cur)); ++ } ++#endif /* BCMDBG */ ++ ++ if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { ++ DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", ++ di->name, len)); ++ brcmu_pkt_buf_free_skb(head); ++ di->dma.rxgiants++; ++ goto next_frame; ++ } ++ } ++ ++ return head; ++} ++ ++static bool dma64_rxidle(struct dma_info *di) ++{ ++ DMA_TRACE(("%s: dma_rxidle\n", di->name)); ++ ++ if (di->nrxd == 0) ++ return true; ++ ++ return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) == ++ (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK)); ++} ++ ++/* ++ * post receive buffers ++ * return false is refill failed completely and ring is empty this will stall ++ * the rx dma and user might want to call rxfill again asap. This unlikely ++ * happens on memory-rich NIC, but often on memory-constrained dongle ++ */ ++bool dma_rxfill(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ struct sk_buff *p; ++ u16 rxin, rxout; ++ u32 flags = 0; ++ uint n; ++ uint i; ++ dma_addr_t pa; ++ uint extra_offset = 0; ++ bool ring_empty; ++ ++ ring_empty = false; ++ ++ /* ++ * Determine how many receive buffers we're lacking ++ * from the full complement, allocate, initialize, ++ * and post them, then update the chip rx lastdscr. ++ */ ++ ++ rxin = di->rxin; ++ rxout = di->rxout; ++ ++ n = di->nrxpost - nrxdactive(di, rxin, rxout); ++ ++ DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n)); ++ ++ if (di->rxbufsize > BCMEXTRAHDROOM) ++ extra_offset = di->rxextrahdrroom; ++ ++ for (i = 0; i < n; i++) { ++ /* ++ * the di->rxbufsize doesn't include the extra headroom, ++ * we need to add it to the size to be allocated ++ */ ++ p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset); ++ ++ if (p == NULL) { ++ DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", ++ di->name)); ++ if (i == 0 && dma64_rxidle(di)) { ++ DMA_ERROR(("%s: rxfill64: ring is empty !\n", ++ di->name)); ++ ring_empty = true; ++ } ++ di->dma.rxnobuf++; ++ break; ++ } ++ /* reserve an extra headroom, if applicable */ ++ if (extra_offset) ++ skb_pull(p, extra_offset); ++ ++ /* Do a cached write instead of uncached write since DMA_MAP ++ * will flush the cache. ++ */ ++ *(u32 *) (p->data) = 0; ++ ++ pa = pci_map_single(di->pbus, p->data, ++ di->rxbufsize, PCI_DMA_FROMDEVICE); ++ ++ /* save the free packet pointer */ ++ di->rxp[rxout] = p; ++ ++ /* reset flags for each descriptor */ ++ flags = 0; ++ if (rxout == (di->nrxd - 1)) ++ flags = D64_CTRL1_EOT; ++ ++ dma64_dd_upd(di, di->rxd64, pa, rxout, &flags, ++ di->rxbufsize); ++ rxout = nextrxd(di, rxout); ++ } ++ ++ di->rxout = rxout; ++ ++ /* update the chip lastdscr pointer */ ++ W_REG(&di->d64rxregs->ptr, ++ di->rcvptrbase + I2B(rxout, struct dma64desc)); ++ ++ return ring_empty; ++} ++ ++void dma_rxreclaim(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ struct sk_buff *p; ++ ++ DMA_TRACE(("%s: dma_rxreclaim\n", di->name)); ++ ++ while ((p = _dma_getnextrxp(di, true))) ++ brcmu_pkt_buf_free_skb(p); ++} ++ ++void dma_counterreset(struct dma_pub *pub) ++{ ++ /* reset all software counters */ ++ pub->rxgiants = 0; ++ pub->rxnobuf = 0; ++ pub->txnobuf = 0; ++} ++ ++/* get the address of the var in order to change later */ ++unsigned long dma_getvar(struct dma_pub *pub, const char *name) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ if (!strcmp(name, "&txavail")) ++ return (unsigned long)&(di->dma.txavail); ++ return 0; ++} ++ ++/* 64-bit DMA functions */ ++ ++void dma_txinit(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ u32 control = D64_XC_XE; ++ ++ DMA_TRACE(("%s: dma_txinit\n", di->name)); ++ ++ if (di->ntxd == 0) ++ return; ++ ++ di->txin = di->txout = 0; ++ di->dma.txavail = di->ntxd - 1; ++ ++ /* clear tx descriptor ring */ ++ memset(di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc))); ++ ++ /* DMA engine with out alignment requirement requires table to be inited ++ * before enabling the engine ++ */ ++ if (!di->aligndesc_4k) ++ _dma_ddtable_init(di, DMA_TX, di->txdpa); ++ ++ if ((di->dma.dmactrlflags & DMA_CTRL_PEN) == 0) ++ control |= D64_XC_PD; ++ OR_REG(&di->d64txregs->control, control); ++ ++ /* DMA engine with alignment requirement requires table to be inited ++ * before enabling the engine ++ */ ++ if (di->aligndesc_4k) ++ _dma_ddtable_init(di, DMA_TX, di->txdpa); ++} ++ ++void dma_txsuspend(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ DMA_TRACE(("%s: dma_txsuspend\n", di->name)); ++ ++ if (di->ntxd == 0) ++ return; ++ ++ OR_REG(&di->d64txregs->control, D64_XC_SE); ++} ++ ++void dma_txresume(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ DMA_TRACE(("%s: dma_txresume\n", di->name)); ++ ++ if (di->ntxd == 0) ++ return; ++ ++ AND_REG(&di->d64txregs->control, ~D64_XC_SE); ++} ++ ++bool dma_txsuspended(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ ++ return (di->ntxd == 0) || ++ ((R_REG(&di->d64txregs->control) & D64_XC_SE) == ++ D64_XC_SE); ++} ++ ++void dma_txreclaim(struct dma_pub *pub, enum txd_range range) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ struct sk_buff *p; ++ ++ DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, ++ (range == DMA_RANGE_ALL) ? "all" : ++ ((range == ++ DMA_RANGE_TRANSMITTED) ? "transmitted" : ++ "transferred"))); ++ ++ if (di->txin == di->txout) ++ return; ++ ++ while ((p = dma_getnexttxp(pub, range))) { ++ /* For unframed data, we don't have any packets to free */ ++ if (!(di->dma.dmactrlflags & DMA_CTRL_UNFRAMED)) ++ brcmu_pkt_buf_free_skb(p); ++ } ++} ++ ++bool dma_txreset(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ u32 status; ++ ++ if (di->ntxd == 0) ++ return true; ++ ++ /* suspend tx DMA first */ ++ W_REG(&di->d64txregs->control, D64_XC_SE); ++ SPINWAIT(((status = ++ (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) ++ != D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE) ++ && (status != D64_XS0_XS_STOPPED), 10000); ++ ++ W_REG(&di->d64txregs->control, 0); ++ SPINWAIT(((status = ++ (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) ++ != D64_XS0_XS_DISABLED), 10000); ++ ++ /* wait for the last transaction to complete */ ++ udelay(300); ++ ++ return status == D64_XS0_XS_DISABLED; ++} ++ ++bool dma_rxreset(struct dma_pub *pub) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ u32 status; ++ ++ if (di->nrxd == 0) ++ return true; ++ ++ W_REG(&di->d64rxregs->control, 0); ++ SPINWAIT(((status = ++ (R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK)) ++ != D64_RS0_RS_DISABLED), 10000); ++ ++ return status == D64_RS0_RS_DISABLED; ++} ++ ++/* ++ * !! tx entry routine ++ * WARNING: call must check the return value for error. ++ * the error(toss frames) could be fatal and cause many subsequent hard ++ * to debug problems ++ */ ++int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ struct sk_buff *p, *next; ++ unsigned char *data; ++ uint len; ++ u16 txout; ++ u32 flags = 0; ++ dma_addr_t pa; ++ ++ DMA_TRACE(("%s: dma_txfast\n", di->name)); ++ ++ txout = di->txout; ++ ++ /* ++ * Walk the chain of packet buffers ++ * allocating and initializing transmit descriptor entries. ++ */ ++ for (p = p0; p; p = next) { ++ data = p->data; ++ len = p->len; ++ next = p->next; ++ ++ /* return nonzero if out of tx descriptors */ ++ if (nexttxd(di, txout) == di->txin) ++ goto outoftxd; ++ ++ if (len == 0) ++ continue; ++ ++ /* get physical address of buffer start */ ++ pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE); ++ ++ flags = 0; ++ if (p == p0) ++ flags |= D64_CTRL1_SOF; ++ ++ /* With a DMA segment list, Descriptor table is filled ++ * using the segment list instead of looping over ++ * buffers in multi-chain DMA. Therefore, EOF for SGLIST ++ * is when end of segment list is reached. ++ */ ++ if (next == NULL) ++ flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF); ++ if (txout == (di->ntxd - 1)) ++ flags |= D64_CTRL1_EOT; ++ ++ dma64_dd_upd(di, di->txd64, pa, txout, &flags, len); ++ ++ txout = nexttxd(di, txout); ++ } ++ ++ /* if last txd eof not set, fix it */ ++ if (!(flags & D64_CTRL1_EOF)) ++ di->txd64[prevtxd(di, txout)].ctrl1 = ++ cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF); ++ ++ /* save the packet */ ++ di->txp[prevtxd(di, txout)] = p0; ++ ++ /* bump the tx descriptor index */ ++ di->txout = txout; ++ ++ /* kick the chip */ ++ if (commit) ++ W_REG(&di->d64txregs->ptr, ++ di->xmtptrbase + I2B(txout, struct dma64desc)); ++ ++ /* tx flow control */ ++ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; ++ ++ return 0; ++ ++ outoftxd: ++ DMA_ERROR(("%s: dma_txfast: out of txds !!!\n", di->name)); ++ brcmu_pkt_buf_free_skb(p0); ++ di->dma.txavail = 0; ++ di->dma.txnobuf++; ++ return -1; ++} ++ ++/* ++ * Reclaim next completed txd (txds if using chained buffers) in the range ++ * specified and return associated packet. ++ * If range is DMA_RANGE_TRANSMITTED, reclaim descriptors that have be ++ * transmitted as noted by the hardware "CurrDescr" pointer. ++ * If range is DMA_RANGE_TRANSFERED, reclaim descriptors that have be ++ * transferred by the DMA as noted by the hardware "ActiveDescr" pointer. ++ * If range is DMA_RANGE_ALL, reclaim all txd(s) posted to the ring and ++ * return associated packet regardless of the value of hardware pointers. ++ */ ++struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) ++{ ++ struct dma_info *di = (struct dma_info *)pub; ++ u16 start, end, i; ++ u16 active_desc; ++ struct sk_buff *txp; ++ ++ DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, ++ (range == DMA_RANGE_ALL) ? "all" : ++ ((range == ++ DMA_RANGE_TRANSMITTED) ? "transmitted" : ++ "transferred"))); ++ ++ if (di->ntxd == 0) ++ return NULL; ++ ++ txp = NULL; ++ ++ start = di->txin; ++ if (range == DMA_RANGE_ALL) ++ end = di->txout; ++ else { ++ struct dma64regs __iomem *dregs = di->d64txregs; ++ ++ end = (u16) (B2I(((R_REG(&dregs->status0) & ++ D64_XS0_CD_MASK) - ++ di->xmtptrbase) & D64_XS0_CD_MASK, ++ struct dma64desc)); ++ ++ if (range == DMA_RANGE_TRANSFERED) { ++ active_desc = ++ (u16) (R_REG(&dregs->status1) & ++ D64_XS1_AD_MASK); ++ active_desc = ++ (active_desc - di->xmtptrbase) & D64_XS0_CD_MASK; ++ active_desc = B2I(active_desc, struct dma64desc); ++ if (end != active_desc) ++ end = prevtxd(di, active_desc); ++ } ++ } ++ ++ if ((start == 0) && (end > di->txout)) ++ goto bogus; ++ ++ for (i = start; i != end && !txp; i = nexttxd(di, i)) { ++ dma_addr_t pa; ++ uint size; ++ ++ pa = le32_to_cpu(di->txd64[i].addrlow) - di->dataoffsetlow; ++ ++ size = ++ (le32_to_cpu(di->txd64[i].ctrl2) & ++ D64_CTRL2_BC_MASK); ++ ++ di->txd64[i].addrlow = cpu_to_le32(0xdeadbeef); ++ di->txd64[i].addrhigh = cpu_to_le32(0xdeadbeef); ++ ++ txp = di->txp[i]; ++ di->txp[i] = NULL; ++ ++ pci_unmap_single(di->pbus, pa, size, PCI_DMA_TODEVICE); ++ } ++ ++ di->txin = i; ++ ++ /* tx flow control */ ++ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; ++ ++ return txp; ++ ++ bogus: ++ DMA_NONE(("dma_getnexttxp: bogus curr: start %d end %d txout %d " ++ "force %d\n", start, end, di->txout, forceall)); ++ return NULL; ++} ++ ++/* ++ * Mac80211 initiated actions sometimes require packets in the DMA queue to be ++ * modified. The modified portion of the packet is not under control of the DMA ++ * engine. This function calls a caller-supplied function for each packet in ++ * the caller specified dma chain. ++ */ ++void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) ++ (void *pkt, void *arg_a), void *arg_a) ++{ ++ struct dma_info *di = (struct dma_info *) dmah; ++ uint i = di->txin; ++ uint end = di->txout; ++ struct sk_buff *skb; ++ struct ieee80211_tx_info *tx_info; ++ ++ while (i != end) { ++ skb = (struct sk_buff *)di->txp[i]; ++ if (skb != NULL) { ++ tx_info = (struct ieee80211_tx_info *)skb->cb; ++ (callback_fnc)(tx_info, arg_a); ++ } ++ i = nexttxd(di, i); ++ } ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.h.orig 2011-11-09 13:46:58.244800645 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/dma.h 2011-11-09 13:47:16.997566205 -0500 +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_DMA_H_ ++#define _BRCM_DMA_H_ ++ ++#include ++#include "types.h" /* forward structure declarations */ ++ ++/* map/unmap direction */ ++#define DMA_TX 1 /* TX direction for DMA */ ++#define DMA_RX 2 /* RX direction for DMA */ ++ ++/* DMA structure: ++ * support two DMA engines: 32 bits address or 64 bit addressing ++ * basic DMA register set is per channel(transmit or receive) ++ * a pair of channels is defined for convenience ++ */ ++ ++/* 32 bits addressing */ ++ ++struct dma32diag { /* diag access */ ++ u32 fifoaddr; /* diag address */ ++ u32 fifodatalow; /* low 32bits of data */ ++ u32 fifodatahigh; /* high 32bits of data */ ++ u32 pad; /* reserved */ ++}; ++ ++/* 64 bits addressing */ ++ ++/* dma registers per channel(xmt or rcv) */ ++struct dma64regs { ++ u32 control; /* enable, et al */ ++ u32 ptr; /* last descriptor posted to chip */ ++ u32 addrlow; /* desc ring base address low 32-bits (8K aligned) */ ++ u32 addrhigh; /* desc ring base address bits 63:32 (8K aligned) */ ++ u32 status0; /* current descriptor, xmt state */ ++ u32 status1; /* active descriptor, xmt error */ ++}; ++ ++/* range param for dma_getnexttxp() and dma_txreclaim */ ++enum txd_range { ++ DMA_RANGE_ALL = 1, ++ DMA_RANGE_TRANSMITTED, ++ DMA_RANGE_TRANSFERED ++}; ++ ++/* ++ * Exported data structure (read-only) ++ */ ++/* export structure */ ++struct dma_pub { ++ uint txavail; /* # free tx descriptors */ ++ uint dmactrlflags; /* dma control flags */ ++ ++ /* rx error counters */ ++ uint rxgiants; /* rx giant frames */ ++ uint rxnobuf; /* rx out of dma descriptors */ ++ /* tx error counters */ ++ uint txnobuf; /* tx out of dma descriptors */ ++}; ++ ++extern struct dma_pub *dma_attach(char *name, struct si_pub *sih, ++ void __iomem *dmaregstx, void __iomem *dmaregsrx, ++ uint ntxd, uint nrxd, ++ uint rxbufsize, int rxextheadroom, ++ uint nrxpost, uint rxoffset, uint *msg_level); ++ ++void dma_rxinit(struct dma_pub *pub); ++struct sk_buff *dma_rx(struct dma_pub *pub); ++bool dma_rxfill(struct dma_pub *pub); ++bool dma_rxreset(struct dma_pub *pub); ++bool dma_txreset(struct dma_pub *pub); ++void dma_txinit(struct dma_pub *pub); ++int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit); ++void dma_txsuspend(struct dma_pub *pub); ++bool dma_txsuspended(struct dma_pub *pub); ++void dma_txresume(struct dma_pub *pub); ++void dma_txreclaim(struct dma_pub *pub, enum txd_range range); ++void dma_rxreclaim(struct dma_pub *pub); ++void dma_detach(struct dma_pub *pub); ++unsigned long dma_getvar(struct dma_pub *pub, const char *name); ++struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range); ++void dma_counterreset(struct dma_pub *pub); ++ ++void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) ++ (void *pkt, void *arg_a), void *arg_a); ++ ++/* ++ * DMA(Bug) on bcm47xx chips seems to declare that the packet is ready, but ++ * the packet length is not updated yet (by DMA) on the expected time. ++ * Workaround is to hold processor till DMA updates the length, and stay off ++ * the bus to allow DMA update the length in buffer ++ */ ++static inline void dma_spin_for_len(uint len, struct sk_buff *head) ++{ ++#if defined(CONFIG_BCM47XX) ++ if (!len) { ++ while (!(len = *(u16 *) KSEG1ADDR(head->data))) ++ udelay(1); ++ ++ *(u16 *) (head->data) = cpu_to_le16((u16) len); ++ } ++#endif /* defined(CONFIG_BCM47XX) */ ++} ++ ++#endif /* _BRCM_DMA_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c.orig 2011-11-09 13:46:58.245800633 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c 2011-11-09 13:47:16.998566192 -0500 +@@ -0,0 +1,1697 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++#define __UNDEF_NO_VERSION__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nicpci.h" ++#include "phy/phy_int.h" ++#include "d11.h" ++#include "channel.h" ++#include "scb.h" ++#include "pub.h" ++#include "ucode_loader.h" ++#include "mac80211_if.h" ++#include "main.h" ++ ++#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ ++ ++/* Flags we support */ ++#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ ++ FIF_ALLMULTI | \ ++ FIF_FCSFAIL | \ ++ FIF_PLCPFAIL | \ ++ FIF_CONTROL | \ ++ FIF_OTHER_BSS | \ ++ FIF_BCN_PRBRESP_PROMISC) ++ ++#define CHAN2GHZ(channel, freqency, chflags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (freqency), \ ++ .hw_value = (channel), \ ++ .flags = chflags, \ ++ .max_antenna_gain = 0, \ ++ .max_power = 19, \ ++} ++ ++#define CHAN5GHZ(channel, chflags) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + 5*(channel), \ ++ .hw_value = (channel), \ ++ .flags = chflags, \ ++ .max_antenna_gain = 0, \ ++ .max_power = 21, \ ++} ++ ++#define RATE(rate100m, _flags) { \ ++ .bitrate = (rate100m), \ ++ .flags = (_flags), \ ++ .hw_value = (rate100m / 5), \ ++} ++ ++struct firmware_hdr { ++ __le32 offset; ++ __le32 len; ++ __le32 idx; ++}; ++ ++static const char * const brcms_firmwares[MAX_FW_IMAGES] = { ++ "brcm/bcm43xx", ++ NULL ++}; ++ ++static int n_adapters_found; ++ ++MODULE_AUTHOR("Broadcom Corporation"); ++MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); ++MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++/* recognized PCI IDs */ ++static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = { ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */ ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */ ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */ ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */ ++ {0} ++}; ++ ++MODULE_DEVICE_TABLE(pci, brcms_pci_id_table); ++ ++#ifdef BCMDBG ++static int msglevel = 0xdeadbeef; ++module_param(msglevel, int, 0); ++#endif /* BCMDBG */ ++ ++static struct ieee80211_channel brcms_2ghz_chantable[] = { ++ CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN2GHZ(5, 2432, 0), ++ CHAN2GHZ(6, 2437, 0), ++ CHAN2GHZ(7, 2442, 0), ++ CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(12, 2467, ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(13, 2472, ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN2GHZ(14, 2484, ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) ++}; ++ ++static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = { ++ /* UNII-1 */ ++ CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS), ++ /* UNII-2 */ ++ CHAN5GHZ(52, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(56, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(60, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(64, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ /* MID */ ++ CHAN5GHZ(100, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(104, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(108, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(112, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(116, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(120, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(124, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(128, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(132, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(136, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(140, ++ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | ++ IEEE80211_CHAN_NO_HT40MINUS), ++ /* UNII-3 */ ++ CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS), ++ CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS), ++ CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) ++}; ++ ++/* ++ * The rate table is used for both 2.4G and 5G rates. The ++ * latter being a subset as it does not support CCK rates. ++ */ ++static struct ieee80211_rate legacy_ratetable[] = { ++ RATE(10, 0), ++ RATE(20, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(55, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(110, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(60, 0), ++ RATE(90, 0), ++ RATE(120, 0), ++ RATE(180, 0), ++ RATE(240, 0), ++ RATE(360, 0), ++ RATE(480, 0), ++ RATE(540, 0), ++}; ++ ++static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = { ++ .band = IEEE80211_BAND_2GHZ, ++ .channels = brcms_2ghz_chantable, ++ .n_channels = ARRAY_SIZE(brcms_2ghz_chantable), ++ .bitrates = legacy_ratetable, ++ .n_bitrates = ARRAY_SIZE(legacy_ratetable), ++ .ht_cap = { ++ /* from include/linux/ieee80211.h */ ++ .cap = IEEE80211_HT_CAP_GRN_FLD | ++ IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, ++ .ht_supported = true, ++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, ++ .ampdu_density = AMPDU_DEF_MPDU_DENSITY, ++ .mcs = { ++ /* placeholders for now */ ++ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, ++ .rx_highest = cpu_to_le16(500), ++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED} ++ } ++}; ++ ++static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = { ++ .band = IEEE80211_BAND_5GHZ, ++ .channels = brcms_5ghz_nphy_chantable, ++ .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable), ++ .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET, ++ .n_bitrates = ARRAY_SIZE(legacy_ratetable) - ++ BRCMS_LEGACY_5G_RATE_OFFSET, ++ .ht_cap = { ++ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40 | ++ IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */ ++ .ht_supported = true, ++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, ++ .ampdu_density = AMPDU_DEF_MPDU_DENSITY, ++ .mcs = { ++ /* placeholders for now */ ++ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, ++ .rx_highest = cpu_to_le16(500), ++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED} ++ } ++}; ++ ++/* flags the given rate in rateset as requested */ ++static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br) ++{ ++ u32 i; ++ ++ for (i = 0; i < rs->count; i++) { ++ if (rate != (rs->rates[i] & 0x7f)) ++ continue; ++ ++ if (is_br) ++ rs->rates[i] |= BRCMS_RATE_FLAG; ++ else ++ rs->rates[i] &= BRCMS_RATE_MASK; ++ return; ++ } ++} ++ ++static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ++{ ++ struct brcms_info *wl = hw->priv; ++ ++ spin_lock_bh(&wl->lock); ++ if (!wl->pub->up) { ++ wiphy_err(wl->wiphy, "ops->tx called while down\n"); ++ kfree_skb(skb); ++ goto done; ++ } ++ brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); ++ done: ++ spin_unlock_bh(&wl->lock); ++} ++ ++static int brcms_ops_start(struct ieee80211_hw *hw) ++{ ++ struct brcms_info *wl = hw->priv; ++ bool blocked; ++ ++ ieee80211_wake_queues(hw); ++ spin_lock_bh(&wl->lock); ++ blocked = brcms_rfkill_set_hw_state(wl); ++ spin_unlock_bh(&wl->lock); ++ if (!blocked) ++ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); ++ ++ return 0; ++} ++ ++static void brcms_ops_stop(struct ieee80211_hw *hw) ++{ ++ ieee80211_stop_queues(hw); ++} ++ ++static int ++brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ++{ ++ struct brcms_info *wl; ++ int err; ++ ++ /* Just STA for now */ ++ if (vif->type != NL80211_IFTYPE_AP && ++ vif->type != NL80211_IFTYPE_MESH_POINT && ++ vif->type != NL80211_IFTYPE_STATION && ++ vif->type != NL80211_IFTYPE_WDS && ++ vif->type != NL80211_IFTYPE_ADHOC) { ++ wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only" ++ " STA for now\n", __func__, vif->type); ++ return -EOPNOTSUPP; ++ } ++ ++ wl = hw->priv; ++ spin_lock_bh(&wl->lock); ++ if (!wl->pub->up) ++ err = brcms_up(wl); ++ else ++ err = -ENODEV; ++ spin_unlock_bh(&wl->lock); ++ ++ if (err != 0) ++ wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__, ++ err); ++ ++ return err; ++} ++ ++static void ++brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ++{ ++ struct brcms_info *wl; ++ ++ wl = hw->priv; ++ ++ /* put driver in down state */ ++ spin_lock_bh(&wl->lock); ++ brcms_down(wl); ++ spin_unlock_bh(&wl->lock); ++} ++ ++static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) ++{ ++ struct ieee80211_conf *conf = &hw->conf; ++ struct brcms_info *wl = hw->priv; ++ int err = 0; ++ int new_int; ++ struct wiphy *wiphy = hw->wiphy; ++ ++ spin_lock_bh(&wl->lock); ++ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { ++ brcms_c_set_beacon_listen_interval(wl->wlc, ++ conf->listen_interval); ++ } ++ if (changed & IEEE80211_CONF_CHANGE_MONITOR) ++ wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n", ++ __func__, conf->flags & IEEE80211_CONF_MONITOR ? ++ "true" : "false"); ++ if (changed & IEEE80211_CONF_CHANGE_PS) ++ wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n", ++ __func__, conf->flags & IEEE80211_CONF_PS ? ++ "true" : "false"); ++ ++ if (changed & IEEE80211_CONF_CHANGE_POWER) { ++ err = brcms_c_set_tx_power(wl->wlc, conf->power_level); ++ if (err < 0) { ++ wiphy_err(wiphy, "%s: Error setting power_level\n", ++ __func__); ++ goto config_out; ++ } ++ new_int = brcms_c_get_tx_power(wl->wlc); ++ if (new_int != conf->power_level) ++ wiphy_err(wiphy, "%s: Power level req != actual, %d %d" ++ "\n", __func__, conf->power_level, ++ new_int); ++ } ++ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ++ if (conf->channel_type == NL80211_CHAN_HT20 || ++ conf->channel_type == NL80211_CHAN_NO_HT) ++ err = brcms_c_set_channel(wl->wlc, ++ conf->channel->hw_value); ++ else ++ err = -ENOTSUPP; ++ } ++ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) ++ err = brcms_c_set_rate_limit(wl->wlc, ++ conf->short_frame_max_tx_count, ++ conf->long_frame_max_tx_count); ++ ++ config_out: ++ spin_unlock_bh(&wl->lock); ++ return err; ++} ++ ++static void ++brcms_ops_bss_info_changed(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *info, u32 changed) ++{ ++ struct brcms_info *wl = hw->priv; ++ struct wiphy *wiphy = hw->wiphy; ++ ++ if (changed & BSS_CHANGED_ASSOC) { ++ /* association status changed (associated/disassociated) ++ * also implies a change in the AID. ++ */ ++ wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME, ++ __func__, info->assoc ? "" : "dis"); ++ spin_lock_bh(&wl->lock); ++ brcms_c_associate_upd(wl->wlc, info->assoc); ++ spin_unlock_bh(&wl->lock); ++ } ++ if (changed & BSS_CHANGED_ERP_SLOT) { ++ s8 val; ++ ++ /* slot timing changed */ ++ if (info->use_short_slot) ++ val = 1; ++ else ++ val = 0; ++ spin_lock_bh(&wl->lock); ++ brcms_c_set_shortslot_override(wl->wlc, val); ++ spin_unlock_bh(&wl->lock); ++ } ++ ++ if (changed & BSS_CHANGED_HT) { ++ /* 802.11n parameters changed */ ++ u16 mode = info->ht_operation_mode; ++ ++ spin_lock_bh(&wl->lock); ++ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG, ++ mode & IEEE80211_HT_OP_MODE_PROTECTION); ++ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF, ++ mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ++ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS, ++ mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT); ++ spin_unlock_bh(&wl->lock); ++ } ++ if (changed & BSS_CHANGED_BASIC_RATES) { ++ struct ieee80211_supported_band *bi; ++ u32 br_mask, i; ++ u16 rate; ++ struct brcm_rateset rs; ++ int error; ++ ++ /* retrieve the current rates */ ++ spin_lock_bh(&wl->lock); ++ brcms_c_get_current_rateset(wl->wlc, &rs); ++ spin_unlock_bh(&wl->lock); ++ ++ br_mask = info->basic_rates; ++ bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)]; ++ for (i = 0; i < bi->n_bitrates; i++) { ++ /* convert to internal rate value */ ++ rate = (bi->bitrates[i].bitrate << 1) / 10; ++ ++ /* set/clear basic rate flag */ ++ brcms_set_basic_rate(&rs, rate, br_mask & 1); ++ br_mask >>= 1; ++ } ++ ++ /* update the rate set */ ++ spin_lock_bh(&wl->lock); ++ error = brcms_c_set_rateset(wl->wlc, &rs); ++ spin_unlock_bh(&wl->lock); ++ if (error) ++ wiphy_err(wiphy, "changing basic rates failed: %d\n", ++ error); ++ } ++ if (changed & BSS_CHANGED_BEACON_INT) { ++ /* Beacon interval changed */ ++ spin_lock_bh(&wl->lock); ++ brcms_c_set_beacon_period(wl->wlc, info->beacon_int); ++ spin_unlock_bh(&wl->lock); ++ } ++ if (changed & BSS_CHANGED_BSSID) { ++ /* BSSID changed, for whatever reason (IBSS and managed mode) */ ++ spin_lock_bh(&wl->lock); ++ brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); ++ spin_unlock_bh(&wl->lock); ++ } ++ if (changed & BSS_CHANGED_BEACON) ++ /* Beacon data changed, retrieve new beacon (beaconing modes) */ ++ wiphy_err(wiphy, "%s: beacon changed\n", __func__); ++ ++ if (changed & BSS_CHANGED_BEACON_ENABLED) { ++ /* Beaconing should be enabled/disabled (beaconing modes) */ ++ wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__, ++ info->enable_beacon ? "true" : "false"); ++ } ++ ++ if (changed & BSS_CHANGED_CQM) { ++ /* Connection quality monitor config changed */ ++ wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d " ++ " (implement)\n", __func__, info->cqm_rssi_thold, ++ info->cqm_rssi_hyst); ++ } ++ ++ if (changed & BSS_CHANGED_IBSS) { ++ /* IBSS join status changed */ ++ wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__, ++ info->ibss_joined ? "true" : "false"); ++ } ++ ++ if (changed & BSS_CHANGED_ARP_FILTER) { ++ /* Hardware ARP filter address list or state changed */ ++ wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d" ++ " (implement)\n", __func__, info->arp_filter_enabled ? ++ "true" : "false", info->arp_addr_cnt); ++ } ++ ++ if (changed & BSS_CHANGED_QOS) { ++ /* ++ * QoS for this association was enabled/disabled. ++ * Note that it is only ever disabled for station mode. ++ */ ++ wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__, ++ info->qos ? "true" : "false"); ++ } ++ return; ++} ++ ++static void ++brcms_ops_configure_filter(struct ieee80211_hw *hw, ++ unsigned int changed_flags, ++ unsigned int *total_flags, u64 multicast) ++{ ++ struct brcms_info *wl = hw->priv; ++ struct wiphy *wiphy = hw->wiphy; ++ ++ changed_flags &= MAC_FILTERS; ++ *total_flags &= MAC_FILTERS; ++ if (changed_flags & FIF_PROMISC_IN_BSS) ++ wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n"); ++ if (changed_flags & FIF_ALLMULTI) ++ wiphy_err(wiphy, "FIF_ALLMULTI\n"); ++ if (changed_flags & FIF_FCSFAIL) ++ wiphy_err(wiphy, "FIF_FCSFAIL\n"); ++ if (changed_flags & FIF_PLCPFAIL) ++ wiphy_err(wiphy, "FIF_PLCPFAIL\n"); ++ if (changed_flags & FIF_CONTROL) ++ wiphy_err(wiphy, "FIF_CONTROL\n"); ++ if (changed_flags & FIF_OTHER_BSS) ++ wiphy_err(wiphy, "FIF_OTHER_BSS\n"); ++ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { ++ spin_lock_bh(&wl->lock); ++ if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { ++ wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; ++ brcms_c_mac_bcn_promisc_change(wl->wlc, 1); ++ } else { ++ brcms_c_mac_bcn_promisc_change(wl->wlc, 0); ++ wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; ++ } ++ spin_unlock_bh(&wl->lock); ++ } ++ return; ++} ++ ++static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) ++{ ++ struct brcms_info *wl = hw->priv; ++ spin_lock_bh(&wl->lock); ++ brcms_c_scan_start(wl->wlc); ++ spin_unlock_bh(&wl->lock); ++ return; ++} ++ ++static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) ++{ ++ struct brcms_info *wl = hw->priv; ++ spin_lock_bh(&wl->lock); ++ brcms_c_scan_stop(wl->wlc); ++ spin_unlock_bh(&wl->lock); ++ return; ++} ++ ++static int ++brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, ++ const struct ieee80211_tx_queue_params *params) ++{ ++ struct brcms_info *wl = hw->priv; ++ ++ spin_lock_bh(&wl->lock); ++ brcms_c_wme_setparams(wl->wlc, queue, params, true); ++ spin_unlock_bh(&wl->lock); ++ ++ return 0; ++} ++ ++static int ++brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct brcms_info *wl = hw->priv; ++ struct scb *scb = &wl->wlc->pri_scb; ++ ++ brcms_c_init_scb(scb); ++ ++ wl->pub->global_ampdu = &(scb->scb_ampdu); ++ wl->pub->global_ampdu->scb = scb; ++ wl->pub->global_ampdu->max_pdu = 16; ++ ++ sta->ht_cap.ht_supported = true; ++ sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; ++ sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | ++ IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT; ++ ++ /* ++ * minstrel_ht initiates addBA on our behalf by calling ++ * ieee80211_start_tx_ba_session() ++ */ ++ return 0; ++} ++ ++static int ++brcms_ops_ampdu_action(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ enum ieee80211_ampdu_mlme_action action, ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, ++ u8 buf_size) ++{ ++ struct brcms_info *wl = hw->priv; ++ struct scb *scb = &wl->wlc->pri_scb; ++ int status; ++ ++ if (WARN_ON(scb->magic != SCB_MAGIC)) ++ return -EIDRM; ++ switch (action) { ++ case IEEE80211_AMPDU_RX_START: ++ break; ++ case IEEE80211_AMPDU_RX_STOP: ++ break; ++ case IEEE80211_AMPDU_TX_START: ++ spin_lock_bh(&wl->lock); ++ status = brcms_c_aggregatable(wl->wlc, tid); ++ spin_unlock_bh(&wl->lock); ++ if (!status) { ++ wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n", ++ tid); ++ return -EINVAL; ++ } ++ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); ++ break; ++ ++ case IEEE80211_AMPDU_TX_STOP: ++ spin_lock_bh(&wl->lock); ++ brcms_c_ampdu_flush(wl->wlc, sta, tid); ++ spin_unlock_bh(&wl->lock); ++ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ++ break; ++ case IEEE80211_AMPDU_TX_OPERATIONAL: ++ /* ++ * BA window size from ADDBA response ('buf_size') defines how ++ * many outstanding MPDUs are allowed for the BA stream by ++ * recipient and traffic class. 'ampdu_factor' gives maximum ++ * AMPDU size. ++ */ ++ spin_lock_bh(&wl->lock); ++ brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size, ++ (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + ++ sta->ht_cap.ampdu_factor)) - 1); ++ spin_unlock_bh(&wl->lock); ++ /* Power save wakeup */ ++ break; ++ default: ++ wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n", ++ __func__); ++ } ++ ++ return 0; ++} ++ ++static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) ++{ ++ struct brcms_info *wl = hw->priv; ++ bool blocked; ++ ++ spin_lock_bh(&wl->lock); ++ blocked = brcms_c_check_radio_disabled(wl->wlc); ++ spin_unlock_bh(&wl->lock); ++ ++ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); ++} ++ ++static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) ++{ ++ struct brcms_info *wl = hw->priv; ++ ++ no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); ++ ++ /* wait for packet queue and dma fifos to run empty */ ++ spin_lock_bh(&wl->lock); ++ brcms_c_wait_for_tx_completion(wl->wlc, drop); ++ spin_unlock_bh(&wl->lock); ++} ++ ++static const struct ieee80211_ops brcms_ops = { ++ .tx = brcms_ops_tx, ++ .start = brcms_ops_start, ++ .stop = brcms_ops_stop, ++ .add_interface = brcms_ops_add_interface, ++ .remove_interface = brcms_ops_remove_interface, ++ .config = brcms_ops_config, ++ .bss_info_changed = brcms_ops_bss_info_changed, ++ .configure_filter = brcms_ops_configure_filter, ++ .sw_scan_start = brcms_ops_sw_scan_start, ++ .sw_scan_complete = brcms_ops_sw_scan_complete, ++ .conf_tx = brcms_ops_conf_tx, ++ .sta_add = brcms_ops_sta_add, ++ .ampdu_action = brcms_ops_ampdu_action, ++ .rfkill_poll = brcms_ops_rfkill_poll, ++ .flush = brcms_ops_flush, ++}; ++ ++/* ++ * is called in brcms_pci_probe() context, therefore no locking required. ++ */ ++static int brcms_set_hint(struct brcms_info *wl, char *abbrev) ++{ ++ return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); ++} ++ ++void brcms_dpc(unsigned long data) ++{ ++ struct brcms_info *wl; ++ ++ wl = (struct brcms_info *) data; ++ ++ spin_lock_bh(&wl->lock); ++ ++ /* call the common second level interrupt handler */ ++ if (wl->pub->up) { ++ if (wl->resched) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->isr_lock, flags); ++ brcms_c_intrsupd(wl->wlc); ++ spin_unlock_irqrestore(&wl->isr_lock, flags); ++ } ++ ++ wl->resched = brcms_c_dpc(wl->wlc, true); ++ } ++ ++ /* brcms_c_dpc() may bring the driver down */ ++ if (!wl->pub->up) ++ goto done; ++ ++ /* re-schedule dpc */ ++ if (wl->resched) ++ tasklet_schedule(&wl->tasklet); ++ else ++ /* re-enable interrupts */ ++ brcms_intrson(wl); ++ ++ done: ++ spin_unlock_bh(&wl->lock); ++} ++ ++/* ++ * Precondition: Since this function is called in brcms_pci_probe() context, ++ * no locking is required. ++ */ ++static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev) ++{ ++ int status; ++ struct device *device = &pdev->dev; ++ char fw_name[100]; ++ int i; ++ ++ memset(&wl->fw, 0, sizeof(struct brcms_firmware)); ++ for (i = 0; i < MAX_FW_IMAGES; i++) { ++ if (brcms_firmwares[i] == NULL) ++ break; ++ sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], ++ UCODE_LOADER_API_VER); ++ status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); ++ if (status) { ++ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", ++ KBUILD_MODNAME, fw_name); ++ return status; ++ } ++ sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], ++ UCODE_LOADER_API_VER); ++ status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); ++ if (status) { ++ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", ++ KBUILD_MODNAME, fw_name); ++ return status; ++ } ++ wl->fw.hdr_num_entries[i] = ++ wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); ++ } ++ wl->fw.fw_cnt = i; ++ return brcms_ucode_data_init(wl, &wl->ucode); ++} ++ ++/* ++ * Precondition: Since this function is called in brcms_pci_probe() context, ++ * no locking is required. ++ */ ++static void brcms_release_fw(struct brcms_info *wl) ++{ ++ int i; ++ for (i = 0; i < MAX_FW_IMAGES; i++) { ++ release_firmware(wl->fw.fw_bin[i]); ++ release_firmware(wl->fw.fw_hdr[i]); ++ } ++} ++ ++/** ++ * This function frees the WL per-device resources. ++ * ++ * This function frees resources owned by the WL device pointed to ++ * by the wl parameter. ++ * ++ * precondition: can both be called locked and unlocked ++ * ++ */ ++static void brcms_free(struct brcms_info *wl) ++{ ++ struct brcms_timer *t, *next; ++ ++ /* free ucode data */ ++ if (wl->fw.fw_cnt) ++ brcms_ucode_data_free(&wl->ucode); ++ if (wl->irq) ++ free_irq(wl->irq, wl); ++ ++ /* kill dpc */ ++ tasklet_kill(&wl->tasklet); ++ ++ if (wl->pub) ++ brcms_c_module_unregister(wl->pub, "linux", wl); ++ ++ /* free common resources */ ++ if (wl->wlc) { ++ brcms_c_detach(wl->wlc); ++ wl->wlc = NULL; ++ wl->pub = NULL; ++ } ++ ++ /* virtual interface deletion is deferred so we cannot spinwait */ ++ ++ /* wait for all pending callbacks to complete */ ++ while (atomic_read(&wl->callbacks) > 0) ++ schedule(); ++ ++ /* free timers */ ++ for (t = wl->timers; t; t = next) { ++ next = t->next; ++#ifdef BCMDBG ++ kfree(t->name); ++#endif ++ kfree(t); ++ } ++ ++ /* ++ * unregister_netdev() calls get_stats() which may read chip ++ * registers so we cannot unmap the chip registers until ++ * after calling unregister_netdev() . ++ */ ++ if (wl->regsva) ++ iounmap(wl->regsva); ++ ++ wl->regsva = NULL; ++} ++ ++/* ++* called from both kernel as from this kernel module. ++* precondition: perimeter lock is not acquired. ++*/ ++static void brcms_remove(struct pci_dev *pdev) ++{ ++ struct brcms_info *wl; ++ struct ieee80211_hw *hw; ++ int status; ++ ++ hw = pci_get_drvdata(pdev); ++ wl = hw->priv; ++ if (!wl) { ++ pr_err("wl: brcms_remove: pci_get_drvdata failed\n"); ++ return; ++ } ++ ++ spin_lock_bh(&wl->lock); ++ status = brcms_c_chipmatch(pdev->vendor, pdev->device); ++ spin_unlock_bh(&wl->lock); ++ if (!status) { ++ wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch " ++ "failed\n"); ++ return; ++ } ++ if (wl->wlc) { ++ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); ++ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); ++ ieee80211_unregister_hw(hw); ++ spin_lock_bh(&wl->lock); ++ brcms_down(wl); ++ spin_unlock_bh(&wl->lock); ++ } ++ pci_disable_device(pdev); ++ ++ brcms_free(wl); ++ ++ pci_set_drvdata(pdev, NULL); ++ ieee80211_free_hw(hw); ++} ++ ++static irqreturn_t brcms_isr(int irq, void *dev_id) ++{ ++ struct brcms_info *wl; ++ bool ours, wantdpc; ++ ++ wl = (struct brcms_info *) dev_id; ++ ++ spin_lock(&wl->isr_lock); ++ ++ /* call common first level interrupt handler */ ++ ours = brcms_c_isr(wl->wlc, &wantdpc); ++ if (ours) { ++ /* if more to do... */ ++ if (wantdpc) { ++ ++ /* ...and call the second level interrupt handler */ ++ /* schedule dpc */ ++ tasklet_schedule(&wl->tasklet); ++ } ++ } ++ ++ spin_unlock(&wl->isr_lock); ++ ++ return IRQ_RETVAL(ours); ++} ++ ++/* ++ * is called in brcms_pci_probe() context, therefore no locking required. ++ */ ++static int ieee_hw_rate_init(struct ieee80211_hw *hw) ++{ ++ struct brcms_info *wl = hw->priv; ++ struct brcms_c_info *wlc = wl->wlc; ++ struct ieee80211_supported_band *band; ++ int has_5g = 0; ++ u16 phy_type; ++ ++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; ++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; ++ ++ phy_type = brcms_c_get_phy_type(wl->wlc, 0); ++ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { ++ band = &wlc->bandstate[BAND_2G_INDEX]->band; ++ *band = brcms_band_2GHz_nphy_template; ++ if (phy_type == PHY_TYPE_LCN) { ++ /* Single stream */ ++ band->ht_cap.mcs.rx_mask[1] = 0; ++ band->ht_cap.mcs.rx_highest = cpu_to_le16(72); ++ } ++ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; ++ } else { ++ return -EPERM; ++ } ++ ++ /* Assume all bands use the same phy. True for 11n devices. */ ++ if (wl->pub->_nbands > 1) { ++ has_5g++; ++ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { ++ band = &wlc->bandstate[BAND_5G_INDEX]->band; ++ *band = brcms_band_5GHz_nphy_template; ++ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band; ++ } else { ++ return -EPERM; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * is called in brcms_pci_probe() context, therefore no locking required. ++ */ ++static int ieee_hw_init(struct ieee80211_hw *hw) ++{ ++ hw->flags = IEEE80211_HW_SIGNAL_DBM ++ /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */ ++ | IEEE80211_HW_REPORTS_TX_ACK_STATUS ++ | IEEE80211_HW_AMPDU_AGGREGATION; ++ ++ hw->extra_tx_headroom = brcms_c_get_header_len(); ++ hw->queues = N_TX_QUEUES; ++ hw->max_rates = 2; /* Primary rate and 1 fallback rate */ ++ ++ /* channel change time is dependent on chip and band */ ++ hw->channel_change_time = 7 * 1000; ++ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); ++ ++ hw->rate_control_algorithm = "minstrel_ht"; ++ ++ hw->sta_data_size = 0; ++ return ieee_hw_rate_init(hw); ++} ++ ++/** ++ * attach to the WL device. ++ * ++ * Attach to the WL device identified by vendor and device parameters. ++ * regs is a host accessible memory address pointing to WL device registers. ++ * ++ * brcms_attach is not defined as static because in the case where no bus ++ * is defined, wl_attach will never be called, and thus, gcc will issue ++ * a warning that this function is defined but not used if we declare ++ * it as static. ++ * ++ * ++ * is called in brcms_pci_probe() context, therefore no locking required. ++ */ ++static struct brcms_info *brcms_attach(u16 vendor, u16 device, ++ resource_size_t regs, ++ struct pci_dev *btparam, uint irq) ++{ ++ struct brcms_info *wl = NULL; ++ int unit, err; ++ struct ieee80211_hw *hw; ++ u8 perm[ETH_ALEN]; ++ ++ unit = n_adapters_found; ++ err = 0; ++ ++ if (unit < 0) ++ return NULL; ++ ++ /* allocate private info */ ++ hw = pci_get_drvdata(btparam); /* btparam == pdev */ ++ if (hw != NULL) ++ wl = hw->priv; ++ if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) ++ return NULL; ++ wl->wiphy = hw->wiphy; ++ ++ atomic_set(&wl->callbacks, 0); ++ ++ /* setup the bottom half handler */ ++ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); ++ ++ wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ); ++ if (wl->regsva == NULL) { ++ wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit); ++ goto fail; ++ } ++ spin_lock_init(&wl->lock); ++ spin_lock_init(&wl->isr_lock); ++ ++ /* prepare ucode */ ++ if (brcms_request_fw(wl, btparam) < 0) { ++ wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " ++ "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); ++ brcms_release_fw(wl); ++ brcms_remove(btparam); ++ return NULL; ++ } ++ ++ /* common load-time initialization */ ++ wl->wlc = brcms_c_attach(wl, vendor, device, unit, false, ++ wl->regsva, btparam, &err); ++ brcms_release_fw(wl); ++ if (!wl->wlc) { ++ wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", ++ KBUILD_MODNAME, err); ++ goto fail; ++ } ++ wl->pub = brcms_c_pub(wl->wlc); ++ ++ wl->pub->ieee_hw = hw; ++ ++ /* disable mpc */ ++ brcms_c_set_radio_mpc(wl->wlc, false); ++ ++ /* register our interrupt handler */ ++ if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { ++ wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); ++ goto fail; ++ } ++ wl->irq = irq; ++ ++ /* register module */ ++ brcms_c_module_register(wl->pub, "linux", wl, NULL); ++ ++ if (ieee_hw_init(hw)) { ++ wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, ++ __func__); ++ goto fail; ++ } ++ ++ memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); ++ if (WARN_ON(!is_valid_ether_addr(perm))) ++ goto fail; ++ SET_IEEE80211_PERM_ADDR(hw, perm); ++ ++ err = ieee80211_register_hw(hw); ++ if (err) ++ wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" ++ "%d\n", __func__, err); ++ ++ if (wl->pub->srom_ccode[0]) ++ err = brcms_set_hint(wl, wl->pub->srom_ccode); ++ else ++ err = brcms_set_hint(wl, "US"); ++ if (err) ++ wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", ++ __func__, err); ++ ++ n_adapters_found++; ++ return wl; ++ ++fail: ++ brcms_free(wl); ++ return NULL; ++} ++ ++ ++ ++/** ++ * determines if a device is a WL device, and if so, attaches it. ++ * ++ * This function determines if a device pointed to by pdev is a WL device, ++ * and if so, performs a brcms_attach() on it. ++ * ++ * Perimeter lock is initialized in the course of this function. ++ */ ++static int __devinit ++brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ int rc; ++ struct brcms_info *wl; ++ struct ieee80211_hw *hw; ++ u32 val; ++ ++ dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n", ++ pdev->bus->number, PCI_SLOT(pdev->devfn), ++ PCI_FUNC(pdev->devfn), pdev->irq); ++ ++ if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || ++ ((pdev->device != 0x0576) && ++ ((pdev->device & 0xff00) != 0x4300) && ++ ((pdev->device & 0xff00) != 0x4700) && ++ ((pdev->device < 43000) || (pdev->device > 43999)))) ++ return -ENODEV; ++ ++ rc = pci_enable_device(pdev); ++ if (rc) { ++ pr_err("%s: Cannot enable device %d-%d_%d\n", ++ __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), ++ PCI_FUNC(pdev->devfn)); ++ return -ENODEV; ++ } ++ pci_set_master(pdev); ++ ++ pci_read_config_dword(pdev, 0x40, &val); ++ if ((val & 0x0000ff00) != 0) ++ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ++ ++ hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops); ++ if (!hw) { ++ pr_err("%s: ieee80211_alloc_hw failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ SET_IEEE80211_DEV(hw, &pdev->dev); ++ ++ pci_set_drvdata(pdev, hw); ++ ++ memset(hw->priv, 0, sizeof(*wl)); ++ ++ wl = brcms_attach(pdev->vendor, pdev->device, ++ pci_resource_start(pdev, 0), pdev, ++ pdev->irq); ++ ++ if (!wl) { ++ pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME, ++ __func__); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static int brcms_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct brcms_info *wl; ++ struct ieee80211_hw *hw; ++ ++ hw = pci_get_drvdata(pdev); ++ wl = hw->priv; ++ if (!wl) { ++ wiphy_err(wl->wiphy, ++ "brcms_suspend: pci_get_drvdata failed\n"); ++ return -ENODEV; ++ } ++ ++ /* only need to flag hw is down for proper resume */ ++ spin_lock_bh(&wl->lock); ++ wl->pub->hw_up = false; ++ spin_unlock_bh(&wl->lock); ++ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ return pci_set_power_state(pdev, PCI_D3hot); ++} ++ ++static int brcms_resume(struct pci_dev *pdev) ++{ ++ struct brcms_info *wl; ++ struct ieee80211_hw *hw; ++ int err = 0; ++ u32 val; ++ ++ hw = pci_get_drvdata(pdev); ++ wl = hw->priv; ++ if (!wl) { ++ wiphy_err(wl->wiphy, ++ "wl: brcms_resume: pci_get_drvdata failed\n"); ++ return -ENODEV; ++ } ++ ++ err = pci_set_power_state(pdev, PCI_D0); ++ if (err) ++ return err; ++ ++ pci_restore_state(pdev); ++ ++ err = pci_enable_device(pdev); ++ if (err) ++ return err; ++ ++ pci_set_master(pdev); ++ ++ pci_read_config_dword(pdev, 0x40, &val); ++ if ((val & 0x0000ff00) != 0) ++ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ++ ++ /* ++ * done. driver will be put in up state ++ * in brcms_ops_add_interface() call. ++ */ ++ return err; ++} ++ ++static struct pci_driver brcms_pci_driver = { ++ .name = KBUILD_MODNAME, ++ .probe = brcms_pci_probe, ++ .suspend = brcms_suspend, ++ .resume = brcms_resume, ++ .remove = __devexit_p(brcms_remove), ++ .id_table = brcms_pci_id_table, ++}; ++ ++/** ++ * This is the main entry point for the WL driver. ++ * ++ * This function determines if a device pointed to by pdev is a WL device, ++ * and if so, performs a brcms_attach() on it. ++ * ++ */ ++static int __init brcms_module_init(void) ++{ ++ int error = -ENODEV; ++ ++#ifdef BCMDBG ++ if (msglevel != 0xdeadbeef) ++ brcm_msg_level = msglevel; ++#endif /* BCMDBG */ ++ ++ error = pci_register_driver(&brcms_pci_driver); ++ if (!error) ++ return 0; ++ ++ ++ ++ return error; ++} ++ ++/** ++ * This function unloads the WL driver from the system. ++ * ++ * This function unconditionally unloads the WL driver module from the ++ * system. ++ * ++ */ ++static void __exit brcms_module_exit(void) ++{ ++ pci_unregister_driver(&brcms_pci_driver); ++ ++} ++ ++module_init(brcms_module_init); ++module_exit(brcms_module_exit); ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, ++ bool state, int prio) ++{ ++ wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__); ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_init(struct brcms_info *wl) ++{ ++ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); ++ brcms_reset(wl); ++ ++ brcms_c_init(wl->wlc); ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++uint brcms_reset(struct brcms_info *wl) ++{ ++ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); ++ brcms_c_reset(wl->wlc); ++ ++ /* dpc will not be rescheduled */ ++ wl->resched = 0; ++ ++ return 0; ++} ++ ++/* ++ * These are interrupt on/off entry points. Disable interrupts ++ * during interrupt state transition. ++ */ ++void brcms_intrson(struct brcms_info *wl) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->isr_lock, flags); ++ brcms_c_intrson(wl->wlc); ++ spin_unlock_irqrestore(&wl->isr_lock, flags); ++} ++ ++u32 brcms_intrsoff(struct brcms_info *wl) ++{ ++ unsigned long flags; ++ u32 status; ++ ++ spin_lock_irqsave(&wl->isr_lock, flags); ++ status = brcms_c_intrsoff(wl->wlc); ++ spin_unlock_irqrestore(&wl->isr_lock, flags); ++ return status; ++} ++ ++void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->isr_lock, flags); ++ brcms_c_intrsrestore(wl->wlc, macintmask); ++ spin_unlock_irqrestore(&wl->isr_lock, flags); ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++int brcms_up(struct brcms_info *wl) ++{ ++ int error = 0; ++ ++ if (wl->pub->up) ++ return 0; ++ ++ error = brcms_c_up(wl->wlc); ++ ++ return error; ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_down(struct brcms_info *wl) ++{ ++ uint callbacks, ret_val = 0; ++ ++ /* call common down function */ ++ ret_val = brcms_c_down(wl->wlc); ++ callbacks = atomic_read(&wl->callbacks) - ret_val; ++ ++ /* wait for down callbacks to complete */ ++ spin_unlock_bh(&wl->lock); ++ ++ /* For HIGH_only driver, it's important to actually schedule other work, ++ * not just spin wait since everything runs at schedule level ++ */ ++ SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); ++ ++ spin_lock_bh(&wl->lock); ++} ++ ++/* ++* precondition: perimeter lock is not acquired ++ */ ++static void _brcms_timer(struct work_struct *work) ++{ ++ struct brcms_timer *t = container_of(work, struct brcms_timer, ++ dly_wrk.work); ++ ++ spin_lock_bh(&t->wl->lock); ++ ++ if (t->set) { ++ if (t->periodic) { ++ atomic_inc(&t->wl->callbacks); ++ ieee80211_queue_delayed_work(t->wl->pub->ieee_hw, ++ &t->dly_wrk, ++ msecs_to_jiffies(t->ms)); ++ } else { ++ t->set = false; ++ } ++ ++ t->fn(t->arg); ++ } ++ ++ atomic_dec(&t->wl->callbacks); ++ ++ spin_unlock_bh(&t->wl->lock); ++} ++ ++/* ++ * Adds a timer to the list. Caller supplies a timer function. ++ * Is called from wlc. ++ * ++ * precondition: perimeter lock has been acquired ++ */ ++struct brcms_timer *brcms_init_timer(struct brcms_info *wl, ++ void (*fn) (void *arg), ++ void *arg, const char *name) ++{ ++ struct brcms_timer *t; ++ ++ t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC); ++ if (!t) ++ return NULL; ++ ++ INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer); ++ t->wl = wl; ++ t->fn = fn; ++ t->arg = arg; ++ t->next = wl->timers; ++ wl->timers = t; ++ ++#ifdef BCMDBG ++ t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); ++ if (t->name) ++ strcpy(t->name, name); ++#endif ++ ++ return t; ++} ++ ++/* ++ * adds only the kernel timer since it's going to be more accurate ++ * as well as it's easier to make it periodic ++ * ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) ++{ ++ struct ieee80211_hw *hw = t->wl->pub->ieee_hw; ++ ++#ifdef BCMDBG ++ if (t->set) ++ wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n", ++ __func__, t->name, periodic); ++#endif ++ t->ms = ms; ++ t->periodic = (bool) periodic; ++ t->set = true; ++ ++ atomic_inc(&t->wl->callbacks); ++ ++ ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); ++} ++ ++/* ++ * return true if timer successfully deleted, false if still pending ++ * ++ * precondition: perimeter lock has been acquired ++ */ ++bool brcms_del_timer(struct brcms_timer *t) ++{ ++ if (t->set) { ++ t->set = false; ++ if (!cancel_delayed_work(&t->dly_wrk)) ++ return false; ++ ++ atomic_dec(&t->wl->callbacks); ++ } ++ ++ return true; ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_free_timer(struct brcms_timer *t) ++{ ++ struct brcms_info *wl = t->wl; ++ struct brcms_timer *tmp; ++ ++ /* delete the timer in case it is active */ ++ brcms_del_timer(t); ++ ++ if (wl->timers == t) { ++ wl->timers = wl->timers->next; ++#ifdef BCMDBG ++ kfree(t->name); ++#endif ++ kfree(t); ++ return; ++ ++ } ++ ++ tmp = wl->timers; ++ while (tmp) { ++ if (tmp->next == t) { ++ tmp->next = t->next; ++#ifdef BCMDBG ++ kfree(t->name); ++#endif ++ kfree(t); ++ return; ++ } ++ tmp = tmp->next; ++ } ++ ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) ++{ ++ int i, entry; ++ const u8 *pdata; ++ struct firmware_hdr *hdr; ++ for (i = 0; i < wl->fw.fw_cnt; i++) { ++ hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; ++ for (entry = 0; entry < wl->fw.hdr_num_entries[i]; ++ entry++, hdr++) { ++ u32 len = le32_to_cpu(hdr->len); ++ if (le32_to_cpu(hdr->idx) == idx) { ++ pdata = wl->fw.fw_bin[i]->data + ++ le32_to_cpu(hdr->offset); ++ *pbuf = kmalloc(len, GFP_ATOMIC); ++ if (*pbuf == NULL) ++ goto fail; ++ ++ memcpy(*pbuf, pdata, len); ++ return 0; ++ } ++ } ++ } ++ wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n", ++ idx); ++ *pbuf = NULL; ++fail: ++ return -ENODATA; ++} ++ ++/* ++ * Precondition: Since this function is called in brcms_pci_probe() context, ++ * no locking is required. ++ */ ++int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) ++{ ++ int i, entry; ++ const u8 *pdata; ++ struct firmware_hdr *hdr; ++ for (i = 0; i < wl->fw.fw_cnt; i++) { ++ hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; ++ for (entry = 0; entry < wl->fw.hdr_num_entries[i]; ++ entry++, hdr++) { ++ if (le32_to_cpu(hdr->idx) == idx) { ++ pdata = wl->fw.fw_bin[i]->data + ++ le32_to_cpu(hdr->offset); ++ if (le32_to_cpu(hdr->len) != 4) { ++ wiphy_err(wl->wiphy, ++ "ERROR: fw hdr len\n"); ++ return -ENOMSG; ++ } ++ *n_bytes = le32_to_cpu(*((__le32 *) pdata)); ++ return 0; ++ } ++ } ++ } ++ wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx); ++ return -ENOMSG; ++} ++ ++/* ++ * precondition: can both be called locked and unlocked ++ */ ++void brcms_ucode_free_buf(void *p) ++{ ++ kfree(p); ++} ++ ++/* ++ * checks validity of all firmware images loaded from user space ++ * ++ * Precondition: Since this function is called in brcms_pci_probe() context, ++ * no locking is required. ++ */ ++int brcms_check_firmwares(struct brcms_info *wl) ++{ ++ int i; ++ int entry; ++ int rc = 0; ++ const struct firmware *fw; ++ const struct firmware *fw_hdr; ++ struct firmware_hdr *ucode_hdr; ++ for (i = 0; i < MAX_FW_IMAGES && rc == 0; i++) { ++ fw = wl->fw.fw_bin[i]; ++ fw_hdr = wl->fw.fw_hdr[i]; ++ if (fw == NULL && fw_hdr == NULL) { ++ break; ++ } else if (fw == NULL || fw_hdr == NULL) { ++ wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n", ++ __func__); ++ rc = -EBADF; ++ } else if (fw_hdr->size % sizeof(struct firmware_hdr)) { ++ wiphy_err(wl->wiphy, "%s: non integral fw hdr file " ++ "size %zu/%zu\n", __func__, fw_hdr->size, ++ sizeof(struct firmware_hdr)); ++ rc = -EBADF; ++ } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { ++ wiphy_err(wl->wiphy, "%s: out of bounds fw file size " ++ "%zu\n", __func__, fw->size); ++ rc = -EBADF; ++ } else { ++ /* check if ucode section overruns firmware image */ ++ ucode_hdr = (struct firmware_hdr *)fw_hdr->data; ++ for (entry = 0; entry < wl->fw.hdr_num_entries[i] && ++ !rc; entry++, ucode_hdr++) { ++ if (le32_to_cpu(ucode_hdr->offset) + ++ le32_to_cpu(ucode_hdr->len) > ++ fw->size) { ++ wiphy_err(wl->wiphy, ++ "%s: conflicting bin/hdr\n", ++ __func__); ++ rc = -EBADF; ++ } ++ } ++ } ++ } ++ if (rc == 0 && wl->fw.fw_cnt != i) { ++ wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__, ++ wl->fw.fw_cnt); ++ rc = -EBADF; ++ } ++ return rc; ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++bool brcms_rfkill_set_hw_state(struct brcms_info *wl) ++{ ++ bool blocked = brcms_c_check_radio_disabled(wl->wlc); ++ ++ spin_unlock_bh(&wl->lock); ++ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); ++ if (blocked) ++ wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy); ++ spin_lock_bh(&wl->lock); ++ return blocked; ++} ++ ++/* ++ * precondition: perimeter lock has been acquired ++ */ ++void brcms_msleep(struct brcms_info *wl, uint ms) ++{ ++ spin_unlock_bh(&wl->lock); ++ msleep(ms); ++ spin_lock_bh(&wl->lock); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h.orig 2011-11-09 13:46:58.246800621 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h 2011-11-09 13:47:16.998566192 -0500 +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_MAC80211_IF_H_ ++#define _BRCM_MAC80211_IF_H_ ++ ++#include ++#include ++#include ++ ++#include "ucode_loader.h" ++/* ++ * Starting index for 5G rates in the ++ * legacy rate table. ++ */ ++#define BRCMS_LEGACY_5G_RATE_OFFSET 4 ++ ++/* softmac ioctl definitions */ ++#define BRCMS_SET_SHORTSLOT_OVERRIDE 146 ++ ++struct brcms_timer { ++ struct delayed_work dly_wrk; ++ struct brcms_info *wl; ++ void (*fn) (void *); /* function called upon expiration */ ++ void *arg; /* fixed argument provided to called function */ ++ uint ms; ++ bool periodic; ++ bool set; /* indicates if timer is active */ ++ struct brcms_timer *next; /* for freeing on unload */ ++#ifdef BCMDBG ++ char *name; /* Description of the timer */ ++#endif ++}; ++ ++struct brcms_if { ++ uint subunit; /* WDS/BSS unit */ ++ struct pci_dev *pci_dev; ++}; ++ ++#define MAX_FW_IMAGES 4 ++struct brcms_firmware { ++ u32 fw_cnt; ++ const struct firmware *fw_bin[MAX_FW_IMAGES]; ++ const struct firmware *fw_hdr[MAX_FW_IMAGES]; ++ u32 hdr_num_entries[MAX_FW_IMAGES]; ++}; ++ ++struct brcms_info { ++ struct brcms_pub *pub; /* pointer to public wlc state */ ++ struct brcms_c_info *wlc; /* pointer to private common data */ ++ u32 magic; ++ ++ int irq; ++ ++ spinlock_t lock; /* per-device perimeter lock */ ++ spinlock_t isr_lock; /* per-device ISR synchronization lock */ ++ ++ /* regsva for unmap in brcms_free() */ ++ void __iomem *regsva; /* opaque chip registers virtual address */ ++ ++ /* timer related fields */ ++ atomic_t callbacks; /* # outstanding callback functions */ ++ struct brcms_timer *timers; /* timer cleanup queue */ ++ ++ struct tasklet_struct tasklet; /* dpc tasklet */ ++ bool resched; /* dpc needs to be and is rescheduled */ ++ struct brcms_firmware fw; ++ struct wiphy *wiphy; ++ struct brcms_ucode ucode; ++}; ++ ++/* misc callbacks */ ++extern void brcms_init(struct brcms_info *wl); ++extern uint brcms_reset(struct brcms_info *wl); ++extern void brcms_intrson(struct brcms_info *wl); ++extern u32 brcms_intrsoff(struct brcms_info *wl); ++extern void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask); ++extern int brcms_up(struct brcms_info *wl); ++extern void brcms_down(struct brcms_info *wl); ++extern void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, ++ bool state, int prio); ++extern bool brcms_rfkill_set_hw_state(struct brcms_info *wl); ++ ++/* timer functions */ ++extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, ++ void (*fn) (void *arg), void *arg, ++ const char *name); ++extern void brcms_free_timer(struct brcms_timer *timer); ++extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); ++extern bool brcms_del_timer(struct brcms_timer *timer); ++extern void brcms_msleep(struct brcms_info *wl, uint ms); ++extern void brcms_dpc(unsigned long data); ++extern void brcms_timer(struct brcms_timer *t); ++ ++#endif /* _BRCM_MAC80211_IF_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.c.orig 2011-11-09 13:46:58.250800570 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.c 2011-11-09 13:47:17.004566116 -0500 +@@ -0,0 +1,8775 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rate.h" ++#include "scb.h" ++#include "phy/phy_hal.h" ++#include "channel.h" ++#include "antsel.h" ++#include "stf.h" ++#include "ampdu.h" ++#include "mac80211_if.h" ++#include "ucode_loader.h" ++#include "main.h" ++ ++/* ++ * Indication for txflowcontrol that all priority bits in ++ * TXQ_STOP_FOR_PRIOFC_MASK are to be considered. ++ */ ++#define ALLPRIO -1 ++ ++/* ++ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. ++ */ ++#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1) ++ ++/* watchdog timer, in unit of ms */ ++#define TIMER_INTERVAL_WATCHDOG 1000 ++/* radio monitor timer, in unit of ms */ ++#define TIMER_INTERVAL_RADIOCHK 800 ++ ++/* Max MPC timeout, in unit of watchdog */ ++#ifndef BRCMS_MPC_MAX_DELAYCNT ++#define BRCMS_MPC_MAX_DELAYCNT 10 ++#endif ++ ++/* Min MPC timeout, in unit of watchdog */ ++#define BRCMS_MPC_MIN_DELAYCNT 1 ++#define BRCMS_MPC_THRESHOLD 3 /* MPC count threshold level */ ++ ++/* beacon interval, in unit of 1024TU */ ++#define BEACON_INTERVAL_DEFAULT 100 ++/* DTIM interval, in unit of beacon interval */ ++#define DTIM_INTERVAL_DEFAULT 3 ++ ++/* Scale down delays to accommodate QT slow speed */ ++/* beacon interval, in unit of 1024TU */ ++#define BEACON_INTERVAL_DEF_QT 20 ++/* DTIM interval, in unit of beacon interval */ ++#define DTIM_INTERVAL_DEF_QT 1 ++ ++#define TBTT_ALIGN_LEEWAY_US 100 /* min leeway before first TBTT in us */ ++ ++/* n-mode support capability */ ++/* 2x2 includes both 1x1 & 2x2 devices ++ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and ++ * control it independently ++ */ ++#define WL_11N_2x2 1 ++#define WL_11N_3x3 3 ++#define WL_11N_4x4 4 ++ ++/* define 11n feature disable flags */ ++#define WLFEATURE_DISABLE_11N 0x00000001 ++#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 ++#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 ++#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 ++#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 ++#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 ++#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 ++#define WLFEATURE_DISABLE_11N_GF 0x00000080 ++ ++#define EDCF_ACI_MASK 0x60 ++#define EDCF_ACI_SHIFT 5 ++#define EDCF_ECWMIN_MASK 0x0f ++#define EDCF_ECWMAX_SHIFT 4 ++#define EDCF_AIFSN_MASK 0x0f ++#define EDCF_AIFSN_MAX 15 ++#define EDCF_ECWMAX_MASK 0xf0 ++ ++#define EDCF_AC_BE_TXOP_STA 0x0000 ++#define EDCF_AC_BK_TXOP_STA 0x0000 ++#define EDCF_AC_VO_ACI_STA 0x62 ++#define EDCF_AC_VO_ECW_STA 0x32 ++#define EDCF_AC_VI_ACI_STA 0x42 ++#define EDCF_AC_VI_ECW_STA 0x43 ++#define EDCF_AC_BK_ECW_STA 0xA4 ++#define EDCF_AC_VI_TXOP_STA 0x005e ++#define EDCF_AC_VO_TXOP_STA 0x002f ++#define EDCF_AC_BE_ACI_STA 0x03 ++#define EDCF_AC_BE_ECW_STA 0xA4 ++#define EDCF_AC_BK_ACI_STA 0x27 ++#define EDCF_AC_VO_TXOP_AP 0x002f ++ ++#define EDCF_TXOP2USEC(txop) ((txop) << 5) ++#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) ++ ++#define APHY_SYMBOL_TIME 4 ++#define APHY_PREAMBLE_TIME 16 ++#define APHY_SIGNAL_TIME 4 ++#define APHY_SIFS_TIME 16 ++#define APHY_SERVICE_NBITS 16 ++#define APHY_TAIL_NBITS 6 ++#define BPHY_SIFS_TIME 10 ++#define BPHY_PLCP_SHORT_TIME 96 ++ ++#define PREN_PREAMBLE 24 ++#define PREN_MM_EXT 12 ++#define PREN_PREAMBLE_EXT 4 ++ ++#define DOT11_MAC_HDR_LEN 24 ++#define DOT11_ACK_LEN 10 ++#define DOT11_BA_LEN 4 ++#define DOT11_OFDM_SIGNAL_EXTENSION 6 ++#define DOT11_MIN_FRAG_LEN 256 ++#define DOT11_RTS_LEN 16 ++#define DOT11_CTS_LEN 10 ++#define DOT11_BA_BITMAP_LEN 128 ++#define DOT11_MIN_BEACON_PERIOD 1 ++#define DOT11_MAX_BEACON_PERIOD 0xFFFF ++#define DOT11_MAXNUMFRAGS 16 ++#define DOT11_MAX_FRAG_LEN 2346 ++ ++#define BPHY_PLCP_TIME 192 ++#define RIFS_11N_TIME 2 ++ ++#define WME_VER 1 ++#define WME_SUBTYPE_PARAM_IE 1 ++#define WME_TYPE 2 ++#define WME_OUI "\x00\x50\xf2" ++ ++#define AC_BE 0 ++#define AC_BK 1 ++#define AC_VI 2 ++#define AC_VO 3 ++ ++#define BCN_TMPL_LEN 512 /* length of the BCN template area */ ++ ++/* brcms_bss_info flag bit values */ ++#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */ ++ ++/* Flags used in brcms_c_txq_info.stopped */ ++/* per prio flow control bits */ ++#define TXQ_STOP_FOR_PRIOFC_MASK 0x000000FF ++/* stop txq enqueue for packet drain */ ++#define TXQ_STOP_FOR_PKT_DRAIN 0x00000100 ++/* stop txq enqueue for ampdu flow control */ ++#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL 0x00000200 ++ ++#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */ ++ ++/* Find basic rate for a given rate */ ++static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec) ++{ ++ if (is_mcs_rate(rspec)) ++ return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK] ++ .leg_ofdm]; ++ return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK]; ++} ++ ++static u16 frametype(u32 rspec, u8 mimoframe) ++{ ++ if (is_mcs_rate(rspec)) ++ return mimoframe; ++ return is_cck_rate(rspec) ? FT_CCK : FT_OFDM; ++} ++ ++/* rfdisable delay timer 500 ms, runs of ALP clock */ ++#define RFDISABLE_DEFAULT 10000000 ++ ++#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */ ++ ++/* precedences numbers for wlc queues. These are twice as may levels as ++ * 802.1D priorities. ++ * Odd numbers are used for HI priority traffic at same precedence levels ++ * These constants are used ONLY by wlc_prio2prec_map. Do not use them ++ * elsewhere. ++ */ ++#define _BRCMS_PREC_NONE 0 /* None = - */ ++#define _BRCMS_PREC_BK 2 /* BK - Background */ ++#define _BRCMS_PREC_BE 4 /* BE - Best-effort */ ++#define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */ ++#define _BRCMS_PREC_CL 8 /* CL - Controlled Load */ ++#define _BRCMS_PREC_VI 10 /* Vi - Video */ ++#define _BRCMS_PREC_VO 12 /* Vo - Voice */ ++#define _BRCMS_PREC_NC 14 /* NC - Network Control */ ++ ++/* The BSS is generating beacons in HW */ ++#define BRCMS_BSSCFG_HW_BCN 0x20 ++ ++#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */ ++#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us */ ++#define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us */ ++#define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */ ++ ++#define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */ ++ ++#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */ ++ ++/* Per-AC retry limit register definitions; uses defs.h bitfield macros */ ++#define EDCF_SHORT_S 0 ++#define EDCF_SFB_S 4 ++#define EDCF_LONG_S 8 ++#define EDCF_LFB_S 12 ++#define EDCF_SHORT_M BITFIELD_MASK(4) ++#define EDCF_SFB_M BITFIELD_MASK(4) ++#define EDCF_LONG_M BITFIELD_MASK(4) ++#define EDCF_LFB_M BITFIELD_MASK(4) ++ ++#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */ ++#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */ ++#define RETRY_LONG_DEF 4 /* Default Long retry count */ ++#define RETRY_SHORT_FB 3 /* Short count for fallback rate */ ++#define RETRY_LONG_FB 2 /* Long count for fallback rate */ ++ ++#define APHY_CWMIN 15 ++#define PHY_CWMAX 1023 ++ ++#define EDCF_AIFSN_MIN 1 ++ ++#define FRAGNUM_MASK 0xF ++ ++#define APHY_SLOT_TIME 9 ++#define BPHY_SLOT_TIME 20 ++ ++#define WL_SPURAVOID_OFF 0 ++#define WL_SPURAVOID_ON1 1 ++#define WL_SPURAVOID_ON2 2 ++ ++/* invalid core flags, use the saved coreflags */ ++#define BRCMS_USE_COREFLAGS 0xffffffff ++ ++/* values for PLCPHdr_override */ ++#define BRCMS_PLCP_AUTO -1 ++#define BRCMS_PLCP_SHORT 0 ++#define BRCMS_PLCP_LONG 1 ++ ++/* values for g_protection_override and n_protection_override */ ++#define BRCMS_PROTECTION_AUTO -1 ++#define BRCMS_PROTECTION_OFF 0 ++#define BRCMS_PROTECTION_ON 1 ++#define BRCMS_PROTECTION_MMHDR_ONLY 2 ++#define BRCMS_PROTECTION_CTS_ONLY 3 ++ ++/* values for g_protection_control and n_protection_control */ ++#define BRCMS_PROTECTION_CTL_OFF 0 ++#define BRCMS_PROTECTION_CTL_LOCAL 1 ++#define BRCMS_PROTECTION_CTL_OVERLAP 2 ++ ++/* values for n_protection */ ++#define BRCMS_N_PROTECTION_OFF 0 ++#define BRCMS_N_PROTECTION_OPTIONAL 1 ++#define BRCMS_N_PROTECTION_20IN40 2 ++#define BRCMS_N_PROTECTION_MIXEDMODE 3 ++ ++/* values for band specific 40MHz capabilities */ ++#define BRCMS_N_BW_20ALL 0 ++#define BRCMS_N_BW_40ALL 1 ++#define BRCMS_N_BW_20IN2G_40IN5G 2 ++ ++/* bitflags for SGI support (sgi_rx iovar) */ ++#define BRCMS_N_SGI_20 0x01 ++#define BRCMS_N_SGI_40 0x02 ++ ++/* defines used by the nrate iovar */ ++/* MSC in use,indicates b0-6 holds an mcs */ ++#define NRATE_MCS_INUSE 0x00000080 ++/* rate/mcs value */ ++#define NRATE_RATE_MASK 0x0000007f ++/* stf mode mask: siso, cdd, stbc, sdm */ ++#define NRATE_STF_MASK 0x0000ff00 ++/* stf mode shift */ ++#define NRATE_STF_SHIFT 8 ++/* bit indicates override both rate & mode */ ++#define NRATE_OVERRIDE 0x80000000 ++/* bit indicate to override mcs only */ ++#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 ++#define NRATE_SGI_MASK 0x00800000 /* sgi mode */ ++#define NRATE_SGI_SHIFT 23 /* sgi mode */ ++#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++#define NRATE_LDPC_SHIFT 22 /* ldpc shift */ ++ ++#define NRATE_STF_SISO 0 /* stf mode SISO */ ++#define NRATE_STF_CDD 1 /* stf mode CDD */ ++#define NRATE_STF_STBC 2 /* stf mode STBC */ ++#define NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#define MAX_DMA_SEGS 4 ++ ++/* Max # of entries in Tx FIFO based on 4kb page size */ ++#define NTXD 256 ++/* Max # of entries in Rx FIFO based on 4kb page size */ ++#define NRXD 256 ++ ++/* try to keep this # rbufs posted to the chip */ ++#define NRXBUFPOST 32 ++ ++/* data msg txq hiwat mark */ ++#define BRCMS_DATAHIWAT 50 ++ ++/* bounded rx loops */ ++#define RXBND 8 /* max # frames to process in brcms_c_recv() */ ++#define TXSBND 8 /* max # tx status to process in wlc_txstatus() */ ++ ++/* ++ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. ++ */ ++#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1) ++ ++/* brcmu_format_flags() bit description structure */ ++struct brcms_c_bit_desc { ++ u32 bit; ++ const char *name; ++}; ++ ++/* ++ * The following table lists the buffer memory allocated to xmt fifos in HW. ++ * the size is in units of 256bytes(one block), total size is HW dependent ++ * ucode has default fifo partition, sw can overwrite if necessary ++ * ++ * This is documented in twiki under the topic UcodeTxFifo. Please ensure ++ * the twiki is updated before making changes. ++ */ ++ ++/* Starting corerev for the fifo size table */ ++#define XMTFIFOTBL_STARTREV 20 ++ ++struct d11init { ++ __le16 addr; ++ __le16 size; ++ __le32 value; ++}; ++ ++struct edcf_acparam { ++ u8 ACI; ++ u8 ECW; ++ u16 TXOP; ++} __packed; ++ ++const u8 prio2fifo[NUMPRIO] = { ++ TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */ ++ TX_AC_BK_FIFO, /* 1 BK AC_BK Background */ ++ TX_AC_BK_FIFO, /* 2 -- AC_BK Background */ ++ TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */ ++ TX_AC_VI_FIFO, /* 4 CL AC_VI Video */ ++ TX_AC_VI_FIFO, /* 5 VI AC_VI Video */ ++ TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */ ++ TX_AC_VO_FIFO /* 7 NC AC_VO Voice */ ++}; ++ ++/* debug/trace */ ++uint brcm_msg_level = ++#if defined(BCMDBG) ++ LOG_ERROR_VAL; ++#else ++ 0; ++#endif /* BCMDBG */ ++ ++/* TX FIFO number to WME/802.1E Access Category */ ++static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE }; ++ ++/* WME/802.1E Access Category to TX FIFO number */ ++static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 }; ++ ++/* 802.1D Priority to precedence queue mapping */ ++const u8 wlc_prio2prec_map[] = { ++ _BRCMS_PREC_BE, /* 0 BE - Best-effort */ ++ _BRCMS_PREC_BK, /* 1 BK - Background */ ++ _BRCMS_PREC_NONE, /* 2 None = - */ ++ _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */ ++ _BRCMS_PREC_CL, /* 4 CL - Controlled Load */ ++ _BRCMS_PREC_VI, /* 5 Vi - Video */ ++ _BRCMS_PREC_VO, /* 6 Vo - Voice */ ++ _BRCMS_PREC_NC, /* 7 NC - Network Control */ ++}; ++ ++static const u16 xmtfifo_sz[][NFIFO] = { ++ /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ ++ {20, 192, 192, 21, 17, 5}, ++ /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ ++ {9, 58, 22, 14, 14, 5}, ++ /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */ ++ {20, 192, 192, 21, 17, 5}, ++ /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */ ++ {20, 192, 192, 21, 17, 5}, ++ /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ ++ {9, 58, 22, 14, 14, 5}, ++}; ++ ++static const u8 acbitmap2maxprio[] = { ++ PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK, ++ PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, ++ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, ++ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO ++}; ++ ++#ifdef BCMDBG ++static const char * const fifo_names[] = { ++ "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" }; ++#else ++static const char fifo_names[6][0]; ++#endif ++ ++#ifdef BCMDBG ++/* pointer to most recently allocated wl/wlc */ ++static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); ++#endif ++ ++/* currently the best mechanism for determining SIFS is the band in use */ ++static u16 get_sifs(struct brcms_band *band) ++{ ++ return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME : ++ BPHY_SIFS_TIME; ++} ++ ++/* ++ * Detect Card removed. ++ * Even checking an sbconfig register read will not false trigger when the core ++ * is in reset it breaks CF address mechanism. Accessing gphy phyversion will ++ * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible ++ * reg with fixed 0/1 pattern (some platforms return all 0). ++ * If clocks are present, call the sb routine which will figure out if the ++ * device is removed. ++ */ ++static bool brcms_deviceremoved(struct brcms_c_info *wlc) ++{ ++ if (!wlc->hw->clk) ++ return ai_deviceremoved(wlc->hw->sih); ++ return (R_REG(&wlc->hw->regs->maccontrol) & ++ (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN; ++} ++ ++/* sum the individual fifo tx pending packet counts */ ++static s16 brcms_txpktpendtot(struct brcms_c_info *wlc) ++{ ++ return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] + ++ wlc->core->txpktpend[2] + wlc->core->txpktpend[3]; ++} ++ ++static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc) ++{ ++ return wlc->pub->_nbands > 1 && !wlc->bandlocked; ++} ++ ++static int brcms_chspec_bw(u16 chanspec) ++{ ++ if (CHSPEC_IS40(chanspec)) ++ return BRCMS_40_MHZ; ++ if (CHSPEC_IS20(chanspec)) ++ return BRCMS_20_MHZ; ++ ++ return BRCMS_10_MHZ; ++} ++ ++/* ++ * return true if Minimum Power Consumption should ++ * be entered, false otherwise ++ */ ++static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc) ++{ ++ return false; ++} ++ ++static bool brcms_c_ismpc(struct brcms_c_info *wlc) ++{ ++ return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc)); ++} ++ ++static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg) ++{ ++ if (cfg == NULL) ++ return; ++ ++ kfree(cfg->current_bss); ++ kfree(cfg); ++} ++ ++static void brcms_c_detach_mfree(struct brcms_c_info *wlc) ++{ ++ if (wlc == NULL) ++ return; ++ ++ brcms_c_bsscfg_mfree(wlc->bsscfg); ++ kfree(wlc->pub); ++ kfree(wlc->modulecb); ++ kfree(wlc->default_bss); ++ kfree(wlc->protection); ++ kfree(wlc->stf); ++ kfree(wlc->bandstate[0]); ++ kfree(wlc->corestate->macstat_snapshot); ++ kfree(wlc->corestate); ++ kfree(wlc->hw->bandstate[0]); ++ kfree(wlc->hw); ++ ++ /* free the wlc */ ++ kfree(wlc); ++ wlc = NULL; ++} ++ ++static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit) ++{ ++ struct brcms_bss_cfg *cfg; ++ ++ cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC); ++ if (cfg == NULL) ++ goto fail; ++ ++ cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC); ++ if (cfg->current_bss == NULL) ++ goto fail; ++ ++ return cfg; ++ ++ fail: ++ brcms_c_bsscfg_mfree(cfg); ++ return NULL; ++} ++ ++static struct brcms_c_info * ++brcms_c_attach_malloc(uint unit, uint *err, uint devid) ++{ ++ struct brcms_c_info *wlc; ++ ++ wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC); ++ if (wlc == NULL) { ++ *err = 1002; ++ goto fail; ++ } ++ ++ /* allocate struct brcms_c_pub state structure */ ++ wlc->pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC); ++ if (wlc->pub == NULL) { ++ *err = 1003; ++ goto fail; ++ } ++ wlc->pub->wlc = wlc; ++ ++ /* allocate struct brcms_hardware state structure */ ++ ++ wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC); ++ if (wlc->hw == NULL) { ++ *err = 1005; ++ goto fail; ++ } ++ wlc->hw->wlc = wlc; ++ ++ wlc->hw->bandstate[0] = ++ kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC); ++ if (wlc->hw->bandstate[0] == NULL) { ++ *err = 1006; ++ goto fail; ++ } else { ++ int i; ++ ++ for (i = 1; i < MAXBANDS; i++) ++ wlc->hw->bandstate[i] = (struct brcms_hw_band *) ++ ((unsigned long)wlc->hw->bandstate[0] + ++ (sizeof(struct brcms_hw_band) * i)); ++ } ++ ++ wlc->modulecb = ++ kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC); ++ if (wlc->modulecb == NULL) { ++ *err = 1009; ++ goto fail; ++ } ++ ++ wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC); ++ if (wlc->default_bss == NULL) { ++ *err = 1010; ++ goto fail; ++ } ++ ++ wlc->bsscfg = brcms_c_bsscfg_malloc(unit); ++ if (wlc->bsscfg == NULL) { ++ *err = 1011; ++ goto fail; ++ } ++ ++ wlc->protection = kzalloc(sizeof(struct brcms_protection), ++ GFP_ATOMIC); ++ if (wlc->protection == NULL) { ++ *err = 1016; ++ goto fail; ++ } ++ ++ wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC); ++ if (wlc->stf == NULL) { ++ *err = 1017; ++ goto fail; ++ } ++ ++ wlc->bandstate[0] = ++ kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC); ++ if (wlc->bandstate[0] == NULL) { ++ *err = 1025; ++ goto fail; ++ } else { ++ int i; ++ ++ for (i = 1; i < MAXBANDS; i++) ++ wlc->bandstate[i] = (struct brcms_band *) ++ ((unsigned long)wlc->bandstate[0] ++ + (sizeof(struct brcms_band)*i)); ++ } ++ ++ wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC); ++ if (wlc->corestate == NULL) { ++ *err = 1026; ++ goto fail; ++ } ++ ++ wlc->corestate->macstat_snapshot = ++ kzalloc(sizeof(struct macstat), GFP_ATOMIC); ++ if (wlc->corestate->macstat_snapshot == NULL) { ++ *err = 1027; ++ goto fail; ++ } ++ ++ return wlc; ++ ++ fail: ++ brcms_c_detach_mfree(wlc); ++ return NULL; ++} ++ ++/* ++ * Update the slot timing for standard 11b/g (20us slots) ++ * or shortslot 11g (9us slots) ++ * The PSM needs to be suspended for this call. ++ */ ++static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw, ++ bool shortslot) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = wlc_hw->regs; ++ ++ if (shortslot) { ++ /* 11g short slot: 11a timing */ ++ W_REG(®s->ifs_slot, 0x0207); /* APHY_SLOT_TIME */ ++ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME); ++ } else { ++ /* 11g long slot: 11b timing */ ++ W_REG(®s->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */ ++ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME); ++ } ++} ++ ++/* ++ * calculate frame duration of a given rate and length, return ++ * time in usec unit ++ */ ++uint ++brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec, ++ u8 preamble_type, uint mac_len) ++{ ++ uint nsyms, dur = 0, Ndps, kNdps; ++ uint rate = rspec2rate(ratespec); ++ ++ if (rate == 0) { ++ wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n", ++ wlc->pub->unit); ++ rate = BRCM_RATE_1M; ++ } ++ ++ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n", ++ wlc->pub->unit, ratespec, preamble_type, mac_len); ++ ++ if (is_mcs_rate(ratespec)) { ++ uint mcs = ratespec & RSPEC_RATE_MASK; ++ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); ++ ++ dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); ++ if (preamble_type == BRCMS_MM_PREAMBLE) ++ dur += PREN_MM_EXT; ++ /* 1000Ndbps = kbps * 4 */ ++ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), ++ rspec_issgi(ratespec)) * 4; ++ ++ if (rspec_stc(ratespec) == 0) ++ nsyms = ++ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + ++ APHY_TAIL_NBITS) * 1000, kNdps); ++ else ++ /* STBC needs to have even number of symbols */ ++ nsyms = ++ 2 * ++ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + ++ APHY_TAIL_NBITS) * 1000, 2 * kNdps); ++ ++ dur += APHY_SYMBOL_TIME * nsyms; ++ if (wlc->band->bandtype == BRCM_BAND_2G) ++ dur += DOT11_OFDM_SIGNAL_EXTENSION; ++ } else if (is_ofdm_rate(rate)) { ++ dur = APHY_PREAMBLE_TIME; ++ dur += APHY_SIGNAL_TIME; ++ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ ++ Ndps = rate * 2; ++ /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */ ++ nsyms = ++ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS), ++ Ndps); ++ dur += APHY_SYMBOL_TIME * nsyms; ++ if (wlc->band->bandtype == BRCM_BAND_2G) ++ dur += DOT11_OFDM_SIGNAL_EXTENSION; ++ } else { ++ /* ++ * calc # bits * 2 so factor of 2 in rate (1/2 mbps) ++ * will divide out ++ */ ++ mac_len = mac_len * 8 * 2; ++ /* calc ceiling of bits/rate = microseconds of air time */ ++ dur = (mac_len + rate - 1) / rate; ++ if (preamble_type & BRCMS_SHORT_PREAMBLE) ++ dur += BPHY_PLCP_SHORT_TIME; ++ else ++ dur += BPHY_PLCP_TIME; ++ } ++ return dur; ++} ++ ++static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, ++ const struct d11init *inits) ++{ ++ int i; ++ u8 __iomem *base; ++ u8 __iomem *addr; ++ u16 size; ++ u32 value; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ base = (u8 __iomem *)wlc_hw->regs; ++ ++ for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) { ++ size = le16_to_cpu(inits[i].size); ++ addr = base + le16_to_cpu(inits[i].addr); ++ value = le32_to_cpu(inits[i].value); ++ if (size == 2) ++ W_REG((u16 __iomem *)addr, value); ++ else if (size == 4) ++ W_REG((u32 __iomem *)addr, value); ++ else ++ break; ++ } ++} ++ ++static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) ++{ ++ u8 idx; ++ u16 addr[] = { ++ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, ++ M_HOST_FLAGS5 ++ }; ++ ++ for (idx = 0; idx < MHFMAX; idx++) ++ brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]); ++} ++ ++static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) ++{ ++ struct wiphy *wiphy = wlc_hw->wlc->wiphy; ++ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; ++ ++ /* init microcode host flags */ ++ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs); ++ ++ /* do band-specific ucode IHR, SHM, and SCR inits */ ++ if (D11REV_IS(wlc_hw->corerev, 23)) { ++ if (BRCMS_ISNPHY(wlc_hw->band)) ++ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16); ++ else ++ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" ++ " %d\n", __func__, wlc_hw->unit, ++ wlc_hw->corerev); ++ } else { ++ if (D11REV_IS(wlc_hw->corerev, 24)) { ++ if (BRCMS_ISLCNPHY(wlc_hw->band)) ++ brcms_c_write_inits(wlc_hw, ++ ucode->d11lcn0bsinitvals24); ++ else ++ wiphy_err(wiphy, "%s: wl%d: unsupported phy in" ++ " core rev %d\n", __func__, ++ wlc_hw->unit, wlc_hw->corerev); ++ } else { ++ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", ++ __func__, wlc_hw->unit, wlc_hw->corerev); ++ } ++ } ++} ++ ++static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk); ++ ++ wlc_hw->phyclk = clk; ++ ++ if (OFF == clk) { /* clear gmode bit, put phy into reset */ ++ ++ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE), ++ (SICF_PRST | SICF_FGC)); ++ udelay(1); ++ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST); ++ udelay(1); ++ ++ } else { /* take phy out of reset */ ++ ++ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC); ++ udelay(1); ++ ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0); ++ udelay(1); ++ ++ } ++} ++ ++/* low-level band switch utility routine */ ++static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, ++ bandunit); ++ ++ wlc_hw->band = wlc_hw->bandstate[bandunit]; ++ ++ /* ++ * BMAC_NOTE: ++ * until we eliminate need for wlc->band refs in low level code ++ */ ++ wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit]; ++ ++ /* set gmode core flag */ ++ if (wlc_hw->sbclk && !wlc_hw->noreset) ++ ai_core_cflags(wlc_hw->sih, SICF_GMODE, ++ ((bandunit == 0) ? SICF_GMODE : 0)); ++} ++ ++/* switch to new band but leave it inactive */ ++static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ u32 macintmask; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); ++ ++ /* disable interrupts */ ++ macintmask = brcms_intrsoff(wlc->wl); ++ ++ /* radio off */ ++ wlc_phy_switch_radio(wlc_hw->band->pi, OFF); ++ ++ brcms_b_core_phy_clk(wlc_hw, OFF); ++ ++ brcms_c_setxband(wlc_hw, bandunit); ++ ++ return macintmask; ++} ++ ++/* process an individual struct tx_status */ ++static bool ++brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) ++{ ++ struct sk_buff *p; ++ uint queue; ++ struct d11txh *txh; ++ struct scb *scb = NULL; ++ bool free_pdu; ++ int tx_rts, tx_frame_count, tx_rts_count; ++ uint totlen, supr_status; ++ bool lastframe; ++ struct ieee80211_hdr *h; ++ u16 mcl; ++ struct ieee80211_tx_info *tx_info; ++ struct ieee80211_tx_rate *txrate; ++ int i; ++ ++ /* discard intermediate indications for ucode with one legitimate case: ++ * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, ++ * but the subsequent tx of DATA failed. so it will start rts/cts ++ * from the beginning (resetting the rts transmission count) ++ */ ++ if (!(txs->status & TX_STATUS_AMPDU) ++ && (txs->status & TX_STATUS_INTERMEDIATE)) { ++ wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n", ++ __func__); ++ return false; ++ } ++ ++ queue = txs->frameid & TXFID_QUEUE_MASK; ++ if (queue >= NFIFO) { ++ p = NULL; ++ goto fatal; ++ } ++ ++ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); ++ if (p == NULL) ++ goto fatal; ++ ++ txh = (struct d11txh *) (p->data); ++ mcl = le16_to_cpu(txh->MacTxControlLow); ++ ++ if (txs->phyerr) { ++ if (brcm_msg_level & LOG_ERROR_VAL) { ++ wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n", ++ txs->phyerr, txh->MainRates); ++ brcms_c_print_txdesc(txh); ++ } ++ brcms_c_print_txstatus(txs); ++ } ++ ++ if (txs->frameid != le16_to_cpu(txh->TxFrameID)) ++ goto fatal; ++ tx_info = IEEE80211_SKB_CB(p); ++ h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); ++ ++ if (tx_info->control.sta) ++ scb = &wlc->pri_scb; ++ ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs); ++ return false; ++ } ++ ++ supr_status = txs->status & TX_STATUS_SUPR_MASK; ++ if (supr_status == TX_STATUS_SUPR_BADCH) ++ BCMMSG(wlc->wiphy, ++ "%s: Pkt tx suppressed, possibly channel %d\n", ++ __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)); ++ ++ tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS; ++ tx_frame_count = ++ (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT; ++ tx_rts_count = ++ (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT; ++ ++ lastframe = !ieee80211_has_morefrags(h->frame_control); ++ ++ if (!lastframe) { ++ wiphy_err(wlc->wiphy, "Not last frame!\n"); ++ } else { ++ /* ++ * Set information to be consumed by Minstrel ht. ++ * ++ * The "fallback limit" is the number of tx attempts a given ++ * MPDU is sent at the "primary" rate. Tx attempts beyond that ++ * limit are sent at the "secondary" rate. ++ * A 'short frame' does not exceed RTS treshold. ++ */ ++ u16 sfbl, /* Short Frame Rate Fallback Limit */ ++ lfbl, /* Long Frame Rate Fallback Limit */ ++ fbl; ++ ++ if (queue < AC_COUNT) { ++ sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], ++ EDCF_SFB); ++ lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], ++ EDCF_LFB); ++ } else { ++ sfbl = wlc->SFBL; ++ lfbl = wlc->LFBL; ++ } ++ ++ txrate = tx_info->status.rates; ++ if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ++ fbl = lfbl; ++ else ++ fbl = sfbl; ++ ++ ieee80211_tx_info_clear_status(tx_info); ++ ++ if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) { ++ /* ++ * rate selection requested a fallback rate ++ * and we used it ++ */ ++ txrate[0].count = fbl; ++ txrate[1].count = tx_frame_count - fbl; ++ } else { ++ /* ++ * rate selection did not request fallback rate, or ++ * we didn't need it ++ */ ++ txrate[0].count = tx_frame_count; ++ /* ++ * rc80211_minstrel.c:minstrel_tx_status() expects ++ * unused rates to be marked with idx = -1 ++ */ ++ txrate[1].idx = -1; ++ txrate[1].count = 0; ++ } ++ ++ /* clear the rest of the rates */ ++ for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) { ++ txrate[i].idx = -1; ++ txrate[i].count = 0; ++ } ++ ++ if (txs->status & TX_STATUS_ACK_RCV) ++ tx_info->flags |= IEEE80211_TX_STAT_ACK; ++ } ++ ++ totlen = brcmu_pkttotlen(p); ++ free_pdu = true; ++ ++ brcms_c_txfifo_complete(wlc, queue, 1); ++ ++ if (lastframe) { ++ p->next = NULL; ++ p->prev = NULL; ++ /* remove PLCP & Broadcom tx descriptor header */ ++ skb_pull(p, D11_PHY_HDR_LEN); ++ skb_pull(p, D11_TXH_LEN); ++ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); ++ } else { ++ wiphy_err(wlc->wiphy, "%s: Not last frame => not calling " ++ "tx_status\n", __func__); ++ } ++ ++ return false; ++ ++ fatal: ++ if (p) ++ brcmu_pkt_buf_free_skb(p); ++ ++ return true; ++ ++} ++ ++/* process tx completion events in BMAC ++ * Return true if more tx status need to be processed. false otherwise. ++ */ ++static bool ++brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) ++{ ++ bool morepending = false; ++ struct brcms_c_info *wlc = wlc_hw->wlc; ++ struct d11regs __iomem *regs; ++ struct tx_status txstatus, *txs; ++ u32 s1, s2; ++ uint n = 0; ++ /* ++ * Param 'max_tx_num' indicates max. # tx status to process before ++ * break out. ++ */ ++ uint max_tx_num = bound ? TXSBND : -1; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ txs = &txstatus; ++ regs = wlc_hw->regs; ++ *fatal = false; ++ while (!(*fatal) ++ && (s1 = R_REG(®s->frmtxstatus)) & TXS_V) { ++ ++ if (s1 == 0xffffffff) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", ++ wlc_hw->unit, __func__); ++ return morepending; ++ } ++ ++ s2 = R_REG(®s->frmtxstatus2); ++ ++ txs->status = s1 & TXS_STATUS_MASK; ++ txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; ++ txs->sequence = s2 & TXS_SEQ_MASK; ++ txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT; ++ txs->lasttxtime = 0; ++ ++ *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); ++ ++ /* !give others some time to run! */ ++ if (++n >= max_tx_num) ++ break; ++ } ++ ++ if (*fatal) ++ return 0; ++ ++ if (n >= max_tx_num) ++ morepending = true; ++ ++ if (!pktq_empty(&wlc->pkt_queue->q)) ++ brcms_c_send_q(wlc); ++ ++ return morepending; ++} ++ ++static void brcms_c_tbtt(struct brcms_c_info *wlc) ++{ ++ if (!wlc->bsscfg->BSS) ++ /* ++ * DirFrmQ is now valid...defer setting until end ++ * of ATIM window ++ */ ++ wlc->qvalid |= MCMD_DIRFRMQVAL; ++} ++ ++/* set initial host flags value */ ++static void ++brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ ++ memset(mhfs, 0, MHFMAX * sizeof(u16)); ++ ++ mhfs[MHF2] |= mhf2_init; ++ ++ /* prohibit use of slowclock on multifunction boards */ ++ if (wlc_hw->boardflags & BFL_NOPLLDOWN) ++ mhfs[MHF1] |= MHF1_FORCEFASTCLK; ++ ++ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) { ++ mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR; ++ mhfs[MHF1] |= MHF1_IQSWAP_WAR; ++ } ++} ++ ++static struct dma64regs __iomem * ++dmareg(struct brcms_hardware *hw, uint direction, uint fifonum) ++{ ++ if (direction == DMA_TX) ++ return &(hw->regs->fifo64regs[fifonum].dmaxmt); ++ return &(hw->regs->fifo64regs[fifonum].dmarcv); ++} ++ ++static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) ++{ ++ uint i; ++ char name[8]; ++ /* ++ * ucode host flag 2 needed for pio mode, independent of band and fifo ++ */ ++ u16 pio_mhf2 = 0; ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ uint unit = wlc_hw->unit; ++ struct wiphy *wiphy = wlc->wiphy; ++ ++ /* name and offsets for dma_attach */ ++ snprintf(name, sizeof(name), "wl%d", unit); ++ ++ if (wlc_hw->di[0] == NULL) { /* Init FIFOs */ ++ int dma_attach_err = 0; ++ ++ /* ++ * FIFO 0 ++ * TX: TX_AC_BK_FIFO (TX AC Background data packets) ++ * RX: RX_FIFO (RX data packets) ++ */ ++ wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, ++ (wme ? dmareg(wlc_hw, DMA_TX, 0) : ++ NULL), dmareg(wlc_hw, DMA_RX, 0), ++ (wme ? NTXD : 0), NRXD, ++ RXBUFSZ, -1, NRXBUFPOST, ++ BRCMS_HWRXOFF, &brcm_msg_level); ++ dma_attach_err |= (NULL == wlc_hw->di[0]); ++ ++ /* ++ * FIFO 1 ++ * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets) ++ * (legacy) TX_DATA_FIFO (TX data packets) ++ * RX: UNUSED ++ */ ++ wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, ++ dmareg(wlc_hw, DMA_TX, 1), NULL, ++ NTXD, 0, 0, -1, 0, 0, ++ &brcm_msg_level); ++ dma_attach_err |= (NULL == wlc_hw->di[1]); ++ ++ /* ++ * FIFO 2 ++ * TX: TX_AC_VI_FIFO (TX AC Video data packets) ++ * RX: UNUSED ++ */ ++ wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, ++ dmareg(wlc_hw, DMA_TX, 2), NULL, ++ NTXD, 0, 0, -1, 0, 0, ++ &brcm_msg_level); ++ dma_attach_err |= (NULL == wlc_hw->di[2]); ++ /* ++ * FIFO 3 ++ * TX: TX_AC_VO_FIFO (TX AC Voice data packets) ++ * (legacy) TX_CTL_FIFO (TX control & mgmt packets) ++ */ ++ wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, ++ dmareg(wlc_hw, DMA_TX, 3), ++ NULL, NTXD, 0, 0, -1, ++ 0, 0, &brcm_msg_level); ++ dma_attach_err |= (NULL == wlc_hw->di[3]); ++/* Cleaner to leave this as if with AP defined */ ++ ++ if (dma_attach_err) { ++ wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed" ++ "\n", unit); ++ return false; ++ } ++ ++ /* get pointer to dma engine tx flow control variable */ ++ for (i = 0; i < NFIFO; i++) ++ if (wlc_hw->di[i]) ++ wlc_hw->txavail[i] = ++ (uint *) dma_getvar(wlc_hw->di[i], ++ "&txavail"); ++ } ++ ++ /* initial ucode host flags */ ++ brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2); ++ ++ return true; ++} ++ ++static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw) ++{ ++ uint j; ++ ++ for (j = 0; j < NFIFO; j++) { ++ if (wlc_hw->di[j]) { ++ dma_detach(wlc_hw->di[j]); ++ wlc_hw->di[j] = NULL; ++ } ++ } ++} ++ ++/* ++ * Initialize brcms_c_info default values ... ++ * may get overrides later in this function ++ * BMAC_NOTES, move low out and resolve the dangling ones ++ */ ++static void brcms_b_info_init(struct brcms_hardware *wlc_hw) ++{ ++ struct brcms_c_info *wlc = wlc_hw->wlc; ++ ++ /* set default sw macintmask value */ ++ wlc->defmacintmask = DEF_MACINTMASK; ++ ++ /* various 802.11g modes */ ++ wlc_hw->shortslot = false; ++ ++ wlc_hw->SFBL = RETRY_SHORT_FB; ++ wlc_hw->LFBL = RETRY_LONG_FB; ++ ++ /* default mac retry limits */ ++ wlc_hw->SRL = RETRY_SHORT_DEF; ++ wlc_hw->LRL = RETRY_LONG_DEF; ++ wlc_hw->chanspec = ch20mhz_chspec(1); ++} ++ ++static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw) ++{ ++ /* delay before first read of ucode state */ ++ udelay(40); ++ ++ /* wait until ucode is no longer asleep */ ++ SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) == ++ DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly); ++} ++ ++/* control chip clock to save power, enable dynamic clock or force fast clock */ ++static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) ++{ ++ if (wlc_hw->sih->cccaps & CC_CAP_PMU) { ++ /* new chips with PMU, CCS_FORCEHT will distribute the HT clock ++ * on backplane, but mac core will still run on ALP(not HT) when ++ * it enters powersave mode, which means the FCA bit may not be ++ * set. Should wakeup mac if driver wants it to run on HT. ++ */ ++ ++ if (wlc_hw->clk) { ++ if (mode == CLK_FAST) { ++ OR_REG(&wlc_hw->regs->clk_ctl_st, ++ CCS_FORCEHT); ++ ++ udelay(64); ++ ++ SPINWAIT(((R_REG ++ (&wlc_hw->regs-> ++ clk_ctl_st) & CCS_HTAVAIL) == 0), ++ PMU_MAX_TRANSITION_DLY); ++ WARN_ON(!(R_REG ++ (&wlc_hw->regs-> ++ clk_ctl_st) & CCS_HTAVAIL)); ++ } else { ++ if ((wlc_hw->sih->pmurev == 0) && ++ (R_REG ++ (&wlc_hw->regs-> ++ clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ))) ++ SPINWAIT(((R_REG ++ (&wlc_hw->regs-> ++ clk_ctl_st) & CCS_HTAVAIL) ++ == 0), ++ PMU_MAX_TRANSITION_DLY); ++ AND_REG(&wlc_hw->regs->clk_ctl_st, ++ ~CCS_FORCEHT); ++ } ++ } ++ wlc_hw->forcefastclk = (mode == CLK_FAST); ++ } else { ++ ++ /* old chips w/o PMU, force HT through cc, ++ * then use FCA to verify mac is running fast clock ++ */ ++ ++ wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode); ++ ++ /* check fast clock is available (if core is not in reset) */ ++ if (wlc_hw->forcefastclk && wlc_hw->clk) ++ WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) & ++ SISF_FCLKA)); ++ ++ /* ++ * keep the ucode wake bit on if forcefastclk is on since we ++ * do not want ucode to put us back to slow clock when it dozes ++ * for PM mode. Code below matches the wake override bit with ++ * current forcefastclk state. Only setting bit in wake_override ++ * instead of waking ucode immediately since old code had this ++ * behavior. Older code set wlc->forcefastclk but only had the ++ * wake happen if the wakup_ucode work (protected by an up ++ * check) was executed just below. ++ */ ++ if (wlc_hw->forcefastclk) ++ mboolset(wlc_hw->wake_override, ++ BRCMS_WAKE_OVERRIDE_FORCEFAST); ++ else ++ mboolclr(wlc_hw->wake_override, ++ BRCMS_WAKE_OVERRIDE_FORCEFAST); ++ } ++} ++ ++/* set or clear ucode host flag bits ++ * it has an optimization for no-change write ++ * it only writes through shared memory when the core has clock; ++ * pre-CLK changes should use wlc_write_mhf to get around the optimization ++ * ++ * ++ * bands values are: BRCM_BAND_AUTO <--- Current band only ++ * BRCM_BAND_5G <--- 5G band only ++ * BRCM_BAND_2G <--- 2G band only ++ * BRCM_BAND_ALL <--- All bands ++ */ ++void ++brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val, ++ int bands) ++{ ++ u16 save; ++ u16 addr[MHFMAX] = { ++ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, ++ M_HOST_FLAGS5 ++ }; ++ struct brcms_hw_band *band; ++ ++ if ((val & ~mask) || idx >= MHFMAX) ++ return; /* error condition */ ++ ++ switch (bands) { ++ /* Current band only or all bands, ++ * then set the band to current band ++ */ ++ case BRCM_BAND_AUTO: ++ case BRCM_BAND_ALL: ++ band = wlc_hw->band; ++ break; ++ case BRCM_BAND_5G: ++ band = wlc_hw->bandstate[BAND_5G_INDEX]; ++ break; ++ case BRCM_BAND_2G: ++ band = wlc_hw->bandstate[BAND_2G_INDEX]; ++ break; ++ default: ++ band = NULL; /* error condition */ ++ } ++ ++ if (band) { ++ save = band->mhfs[idx]; ++ band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val; ++ ++ /* optimization: only write through if changed, and ++ * changed band is the current band ++ */ ++ if (wlc_hw->clk && (band->mhfs[idx] != save) ++ && (band == wlc_hw->band)) ++ brcms_b_write_shm(wlc_hw, addr[idx], ++ (u16) band->mhfs[idx]); ++ } ++ ++ if (bands == BRCM_BAND_ALL) { ++ wlc_hw->bandstate[0]->mhfs[idx] = ++ (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val; ++ wlc_hw->bandstate[1]->mhfs[idx] = ++ (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val; ++ } ++} ++ ++/* set the maccontrol register to desired reset state and ++ * initialize the sw cache of the register ++ */ ++static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw) ++{ ++ /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */ ++ wlc_hw->maccontrol = 0; ++ wlc_hw->suspended_fifos = 0; ++ wlc_hw->wake_override = 0; ++ wlc_hw->mute_override = 0; ++ brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE); ++} ++ ++/* ++ * write the software state of maccontrol and ++ * overrides to the maccontrol register ++ */ ++static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw) ++{ ++ u32 maccontrol = wlc_hw->maccontrol; ++ ++ /* OR in the wake bit if overridden */ ++ if (wlc_hw->wake_override) ++ maccontrol |= MCTL_WAKE; ++ ++ /* set AP and INFRA bits for mute if needed */ ++ if (wlc_hw->mute_override) { ++ maccontrol &= ~(MCTL_AP); ++ maccontrol |= MCTL_INFRA; ++ } ++ ++ W_REG(&wlc_hw->regs->maccontrol, maccontrol); ++} ++ ++/* set or clear maccontrol bits */ ++void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val) ++{ ++ u32 maccontrol; ++ u32 new_maccontrol; ++ ++ if (val & ~mask) ++ return; /* error condition */ ++ maccontrol = wlc_hw->maccontrol; ++ new_maccontrol = (maccontrol & ~mask) | val; ++ ++ /* if the new maccontrol value is the same as the old, nothing to do */ ++ if (new_maccontrol == maccontrol) ++ return; ++ ++ /* something changed, cache the new value */ ++ wlc_hw->maccontrol = new_maccontrol; ++ ++ /* write the new values with overrides applied */ ++ brcms_c_mctrl_write(wlc_hw); ++} ++ ++void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, ++ u32 override_bit) ++{ ++ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) { ++ mboolset(wlc_hw->wake_override, override_bit); ++ return; ++ } ++ ++ mboolset(wlc_hw->wake_override, override_bit); ++ ++ brcms_c_mctrl_write(wlc_hw); ++ brcms_b_wait_for_wake(wlc_hw); ++} ++ ++void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, ++ u32 override_bit) ++{ ++ mboolclr(wlc_hw->wake_override, override_bit); ++ ++ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) ++ return; ++ ++ brcms_c_mctrl_write(wlc_hw); ++} ++ ++/* When driver needs ucode to stop beaconing, it has to make sure that ++ * MCTL_AP is clear and MCTL_INFRA is set ++ * Mode MCTL_AP MCTL_INFRA ++ * AP 1 1 ++ * STA 0 1 <--- This will ensure no beacons ++ * IBSS 0 0 ++ */ ++static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw) ++{ ++ wlc_hw->mute_override = 1; ++ ++ /* if maccontrol already has AP == 0 and INFRA == 1 without this ++ * override, then there is no change to write ++ */ ++ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) ++ return; ++ ++ brcms_c_mctrl_write(wlc_hw); ++} ++ ++/* Clear the override on AP and INFRA bits */ ++static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw) ++{ ++ if (wlc_hw->mute_override == 0) ++ return; ++ ++ wlc_hw->mute_override = 0; ++ ++ /* if maccontrol already has AP == 0 and INFRA == 1 without this ++ * override, then there is no change to write ++ */ ++ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) ++ return; ++ ++ brcms_c_mctrl_write(wlc_hw); ++} ++ ++/* ++ * Write a MAC address to the given match reg offset in the RXE match engine. ++ */ ++static void ++brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, ++ const u8 *addr) ++{ ++ struct d11regs __iomem *regs; ++ u16 mac_l; ++ u16 mac_m; ++ u16 mac_h; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n", ++ wlc_hw->unit); ++ ++ regs = wlc_hw->regs; ++ mac_l = addr[0] | (addr[1] << 8); ++ mac_m = addr[2] | (addr[3] << 8); ++ mac_h = addr[4] | (addr[5] << 8); ++ ++ /* enter the MAC addr into the RXE match registers */ ++ W_REG(®s->rcm_ctl, RCM_INC_DATA | match_reg_offset); ++ W_REG(®s->rcm_mat_data, mac_l); ++ W_REG(®s->rcm_mat_data, mac_m); ++ W_REG(®s->rcm_mat_data, mac_h); ++ ++} ++ ++void ++brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, ++ void *buf) ++{ ++ struct d11regs __iomem *regs; ++ u32 word; ++ __le32 word_le; ++ __be32 word_be; ++ bool be_bit; ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ regs = wlc_hw->regs; ++ W_REG(®s->tplatewrptr, offset); ++ ++ /* if MCTL_BIGEND bit set in mac control register, ++ * the chip swaps data in fifo, as well as data in ++ * template ram ++ */ ++ be_bit = (R_REG(®s->maccontrol) & MCTL_BIGEND) != 0; ++ ++ while (len > 0) { ++ memcpy(&word, buf, sizeof(u32)); ++ ++ if (be_bit) { ++ word_be = cpu_to_be32(word); ++ word = *(u32 *)&word_be; ++ } else { ++ word_le = cpu_to_le32(word); ++ word = *(u32 *)&word_le; ++ } ++ ++ W_REG(®s->tplatewrdata, word); ++ ++ buf = (u8 *) buf + sizeof(u32); ++ len -= sizeof(u32); ++ } ++} ++ ++static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin) ++{ ++ wlc_hw->band->CWmin = newmin; ++ ++ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN); ++ (void)R_REG(&wlc_hw->regs->objaddr); ++ W_REG(&wlc_hw->regs->objdata, newmin); ++} ++ ++static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax) ++{ ++ wlc_hw->band->CWmax = newmax; ++ ++ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX); ++ (void)R_REG(&wlc_hw->regs->objaddr); ++ W_REG(&wlc_hw->regs->objdata, newmax); ++} ++ ++void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) ++{ ++ bool fastclk; ++ ++ /* request FAST clock if not on */ ++ fastclk = wlc_hw->forcefastclk; ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ wlc_phy_bw_state_set(wlc_hw->band->pi, bw); ++ ++ brcms_b_phy_reset(wlc_hw); ++ wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi)); ++ ++ /* restore the clk */ ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); ++} ++ ++static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw) ++{ ++ u16 v; ++ struct brcms_c_info *wlc = wlc_hw->wlc; ++ /* update SYNTHPU_DLY */ ++ ++ if (BRCMS_ISLCNPHY(wlc->band)) ++ v = SYNTHPU_DLY_LPPHY_US; ++ else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3))) ++ v = SYNTHPU_DLY_NPHY_US; ++ else ++ v = SYNTHPU_DLY_BPHY_US; ++ ++ brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v); ++} ++ ++static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw) ++{ ++ u16 phyctl; ++ u16 phytxant = wlc_hw->bmac_phytxant; ++ u16 mask = PHY_TXC_ANT_MASK; ++ ++ /* set the Probe Response frame phy control word */ ++ phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS); ++ phyctl = (phyctl & ~mask) | phytxant; ++ brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl); ++ ++ /* set the Response (ACK/CTS) frame phy control word */ ++ phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD); ++ phyctl = (phyctl & ~mask) | phytxant; ++ brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl); ++} ++ ++static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw, ++ u8 rate) ++{ ++ uint i; ++ u8 plcp_rate = 0; ++ struct plcp_signal_rate_lookup { ++ u8 rate; ++ u8 signal_rate; ++ }; ++ /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */ ++ const struct plcp_signal_rate_lookup rate_lookup[] = { ++ {BRCM_RATE_6M, 0xB}, ++ {BRCM_RATE_9M, 0xF}, ++ {BRCM_RATE_12M, 0xA}, ++ {BRCM_RATE_18M, 0xE}, ++ {BRCM_RATE_24M, 0x9}, ++ {BRCM_RATE_36M, 0xD}, ++ {BRCM_RATE_48M, 0x8}, ++ {BRCM_RATE_54M, 0xC} ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) { ++ if (rate == rate_lookup[i].rate) { ++ plcp_rate = rate_lookup[i].signal_rate; ++ break; ++ } ++ } ++ ++ /* Find the SHM pointer to the rate table entry by looking in the ++ * Direct-map Table ++ */ ++ return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2)); ++} ++ ++static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw) ++{ ++ u8 rate; ++ u8 rates[8] = { ++ BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M, ++ BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M ++ }; ++ u16 entry_ptr; ++ u16 pctl1; ++ uint i; ++ ++ if (!BRCMS_PHY_11N_CAP(wlc_hw->band)) ++ return; ++ ++ /* walk the phy rate table and update the entries */ ++ for (i = 0; i < ARRAY_SIZE(rates); i++) { ++ rate = rates[i]; ++ ++ entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate); ++ ++ /* read the SHM Rate Table entry OFDM PCTL1 values */ ++ pctl1 = ++ brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS); ++ ++ /* modify the value */ ++ pctl1 &= ~PHY_TXC1_MODE_MASK; ++ pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT); ++ ++ /* Update the SHM Rate Table entry OFDM PCTL1 values */ ++ brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS, ++ pctl1); ++ } ++} ++ ++/* band-specific init */ ++static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ ++ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, ++ wlc_hw->band->bandunit); ++ ++ brcms_c_ucode_bsinit(wlc_hw); ++ ++ wlc_phy_init(wlc_hw->band->pi, chanspec); ++ ++ brcms_c_ucode_txant_set(wlc_hw); ++ ++ /* ++ * cwmin is band-specific, update hardware ++ * with value for current band ++ */ ++ brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin); ++ brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax); ++ ++ brcms_b_update_slot_timing(wlc_hw, ++ wlc_hw->band->bandtype == BRCM_BAND_5G ? ++ true : wlc_hw->shortslot); ++ ++ /* write phytype and phyvers */ ++ brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype); ++ brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev); ++ ++ /* ++ * initialize the txphyctl1 rate table since ++ * shmem is shared between bands ++ */ ++ brcms_upd_ofdm_pctl1_table(wlc_hw); ++ ++ brcms_b_upd_synthpu(wlc_hw); ++} ++ ++/* Perform a soft reset of the PHY PLL */ ++void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ ai_corereg(wlc_hw->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_addr), ~0, 0); ++ udelay(1); ++ ai_corereg(wlc_hw->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); ++ udelay(1); ++ ai_corereg(wlc_hw->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), 0x4, 4); ++ udelay(1); ++ ai_corereg(wlc_hw->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); ++ udelay(1); ++} ++ ++/* light way to turn on phy clock without reset for NPHY only ++ * refer to brcms_b_core_phy_clk for full version ++ */ ++void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk) ++{ ++ /* support(necessary for NPHY and HYPHY) only */ ++ if (!BRCMS_ISNPHY(wlc_hw->band)) ++ return; ++ ++ if (ON == clk) ++ ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC); ++ else ++ ai_core_cflags(wlc_hw->sih, SICF_FGC, 0); ++ ++} ++ ++void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk) ++{ ++ if (ON == clk) ++ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE); ++ else ++ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0); ++} ++ ++void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) ++{ ++ struct brcms_phy_pub *pih = wlc_hw->band->pi; ++ u32 phy_bw_clkbits; ++ bool phy_in_reset = false; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ if (pih == NULL) ++ return; ++ ++ phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi); ++ ++ /* Specific reset sequence required for NPHY rev 3 and 4 */ ++ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) && ++ NREV_LE(wlc_hw->band->phyrev, 4)) { ++ /* Set the PHY bandwidth */ ++ ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits); ++ ++ udelay(1); ++ ++ /* Perform a soft reset of the PHY PLL */ ++ brcms_b_core_phypll_reset(wlc_hw); ++ ++ /* reset the PHY */ ++ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE), ++ (SICF_PRST | SICF_PCLKE)); ++ phy_in_reset = true; ++ } else { ++ ai_core_cflags(wlc_hw->sih, ++ (SICF_PRST | SICF_PCLKE | SICF_BWMASK), ++ (SICF_PRST | SICF_PCLKE | phy_bw_clkbits)); ++ } ++ ++ udelay(2); ++ brcms_b_core_phy_clk(wlc_hw, ON); ++ ++ if (pih) ++ wlc_phy_anacore(pih, ON); ++} ++ ++/* switch to and initialize new band */ ++static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit, ++ u16 chanspec) { ++ struct brcms_c_info *wlc = wlc_hw->wlc; ++ u32 macintmask; ++ ++ /* Enable the d11 core before accessing it */ ++ if (!ai_iscoreup(wlc_hw->sih)) { ++ ai_core_reset(wlc_hw->sih, 0, 0); ++ brcms_c_mctrl_reset(wlc_hw); ++ } ++ ++ macintmask = brcms_c_setband_inact(wlc, bandunit); ++ ++ if (!wlc_hw->up) ++ return; ++ ++ brcms_b_core_phy_clk(wlc_hw, ON); ++ ++ /* band-specific initializations */ ++ brcms_b_bsinit(wlc, chanspec); ++ ++ /* ++ * If there are any pending software interrupt bits, ++ * then replace these with a harmless nonzero value ++ * so brcms_c_dpc() will re-enable interrupts when done. ++ */ ++ if (wlc->macintstatus) ++ wlc->macintstatus = MI_DMAINT; ++ ++ /* restore macintmask */ ++ brcms_intrsrestore(wlc->wl, macintmask); ++ ++ /* ucode should still be suspended.. */ ++ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); ++} ++ ++static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw) ++{ ++ ++ /* reject unsupported corerev */ ++ if (!CONF_HAS(D11CONF, wlc_hw->corerev)) { ++ wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n", ++ wlc_hw->corerev); ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Validate some board info parameters */ ++static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw) ++{ ++ uint boardrev = wlc_hw->boardrev; ++ ++ /* 4 bits each for board type, major, minor, and tiny version */ ++ uint brt = (boardrev & 0xf000) >> 12; ++ uint b0 = (boardrev & 0xf00) >> 8; ++ uint b1 = (boardrev & 0xf0) >> 4; ++ uint b2 = boardrev & 0xf; ++ ++ /* voards from other vendors are always considered valid */ ++ if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM) ++ return true; ++ ++ /* do some boardrev sanity checks when boardvendor is Broadcom */ ++ if (boardrev == 0) ++ return false; ++ ++ if (boardrev <= 0xff) ++ return true; ++ ++ if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9) ++ || (b2 > 9)) ++ return false; ++ ++ return true; ++} ++ ++static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw) ++{ ++ enum brcms_srom_id var_id = BRCMS_SROM_MACADDR; ++ char *macaddr; ++ ++ /* If macaddr exists, use it (Sromrev4, CIS, ...). */ ++ macaddr = getvar(wlc_hw->sih, var_id); ++ if (macaddr != NULL) ++ return macaddr; ++ ++ if (wlc_hw->_nbands > 1) ++ var_id = BRCMS_SROM_ET1MACADDR; ++ else ++ var_id = BRCMS_SROM_IL0MACADDR; ++ ++ macaddr = getvar(wlc_hw->sih, var_id); ++ if (macaddr == NULL) ++ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr " ++ "getvar(%d) not found\n", wlc_hw->unit, var_id); ++ ++ return macaddr; ++} ++ ++/* power both the pll and external oscillator on/off */ ++static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want); ++ ++ /* ++ * dont power down if plldown is false or ++ * we must poll hw radio disable ++ */ ++ if (!want && wlc_hw->pllreq) ++ return; ++ ++ if (wlc_hw->sih) ++ ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want); ++ ++ wlc_hw->sbclk = want; ++ if (!wlc_hw->sbclk) { ++ wlc_hw->clk = false; ++ if (wlc_hw->band && wlc_hw->band->pi) ++ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); ++ } ++} ++ ++/* ++ * Return true if radio is disabled, otherwise false. ++ * hw radio disable signal is an external pin, users activate it asynchronously ++ * this function could be called when driver is down and w/o clock ++ * it operates on different registers depending on corerev and boardflag. ++ */ ++static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) ++{ ++ bool v, clk, xtal; ++ u32 resetbits = 0, flags = 0; ++ ++ xtal = wlc_hw->sbclk; ++ if (!xtal) ++ brcms_b_xtal(wlc_hw, ON); ++ ++ /* may need to take core out of reset first */ ++ clk = wlc_hw->clk; ++ if (!clk) { ++ /* ++ * mac no longer enables phyclk automatically when driver ++ * accesses phyreg throughput mac. This can be skipped since ++ * only mac reg is accessed below ++ */ ++ flags |= SICF_PCLKE; ++ ++ /* ++ * AI chip doesn't restore bar0win2 on ++ * hibernation/resume, need sw fixup ++ */ ++ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || ++ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) ++ wlc_hw->regs = (struct d11regs __iomem *) ++ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); ++ ai_core_reset(wlc_hw->sih, flags, resetbits); ++ brcms_c_mctrl_reset(wlc_hw); ++ } ++ ++ v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0); ++ ++ /* put core back into reset */ ++ if (!clk) ++ ai_core_disable(wlc_hw->sih, 0); ++ ++ if (!xtal) ++ brcms_b_xtal(wlc_hw, OFF); ++ ++ return v; ++} ++ ++static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo) ++{ ++ struct dma_pub *di = wlc_hw->di[fifo]; ++ return dma_rxreset(di); ++} ++ ++/* d11 core reset ++ * ensure fask clock during reset ++ * reset dma ++ * reset d11(out of reset) ++ * reset phy(out of reset) ++ * clear software macintstatus for fresh new start ++ * one testing hack wlc_hw->noreset will bypass the d11/phy reset ++ */ ++void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) ++{ ++ struct d11regs __iomem *regs; ++ uint i; ++ bool fastclk; ++ u32 resetbits = 0; ++ ++ if (flags == BRCMS_USE_COREFLAGS) ++ flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ regs = wlc_hw->regs; ++ ++ /* request FAST clock if not on */ ++ fastclk = wlc_hw->forcefastclk; ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ /* reset the dma engines except first time thru */ ++ if (ai_iscoreup(wlc_hw->sih)) { ++ for (i = 0; i < NFIFO; i++) ++ if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) ++ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: " ++ "dma_txreset[%d]: cannot stop dma\n", ++ wlc_hw->unit, __func__, i); ++ ++ if ((wlc_hw->di[RX_FIFO]) ++ && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) ++ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset" ++ "[%d]: cannot stop dma\n", ++ wlc_hw->unit, __func__, RX_FIFO); ++ } ++ /* if noreset, just stop the psm and return */ ++ if (wlc_hw->noreset) { ++ wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */ ++ brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0); ++ return; ++ } ++ ++ /* ++ * mac no longer enables phyclk automatically when driver accesses ++ * phyreg throughput mac, AND phy_reset is skipped at early stage when ++ * band->pi is invalid. need to enable PHY CLK ++ */ ++ flags |= SICF_PCLKE; ++ ++ /* ++ * reset the core ++ * In chips with PMU, the fastclk request goes through d11 core ++ * reg 0x1e0, which is cleared by the core_reset. have to re-request it. ++ * ++ * This adds some delay and we can optimize it by also requesting ++ * fastclk through chipcommon during this period if necessary. But ++ * that has to work coordinate with other driver like mips/arm since ++ * they may touch chipcommon as well. ++ */ ++ wlc_hw->clk = false; ++ ai_core_reset(wlc_hw->sih, flags, resetbits); ++ wlc_hw->clk = true; ++ if (wlc_hw->band && wlc_hw->band->pi) ++ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true); ++ ++ brcms_c_mctrl_reset(wlc_hw); ++ ++ if (wlc_hw->sih->cccaps & CC_CAP_PMU) ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ brcms_b_phy_reset(wlc_hw); ++ ++ /* turn on PHY_PLL */ ++ brcms_b_core_phypll_ctl(wlc_hw, true); ++ ++ /* clear sw intstatus */ ++ wlc_hw->wlc->macintstatus = 0; ++ ++ /* restore the clk setting */ ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); ++} ++ ++/* txfifo sizes needs to be modified(increased) since the newer cores ++ * have more memory. ++ */ ++static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u16 fifo_nu; ++ u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk; ++ u16 txfifo_def, txfifo_def1; ++ u16 txfifo_cmd; ++ ++ /* tx fifos start at TXFIFO_START_BLK from the Base address */ ++ txfifo_startblk = TXFIFO_START_BLK; ++ ++ /* sequence of operations: reset fifo, set fifo size, reset fifo */ ++ for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) { ++ ++ txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu]; ++ txfifo_def = (txfifo_startblk & 0xff) | ++ (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT); ++ txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) | ++ ((((txfifo_endblk - ++ 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT); ++ txfifo_cmd = ++ TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT); ++ ++ W_REG(®s->xmtfifocmd, txfifo_cmd); ++ W_REG(®s->xmtfifodef, txfifo_def); ++ W_REG(®s->xmtfifodef1, txfifo_def1); ++ ++ W_REG(®s->xmtfifocmd, txfifo_cmd); ++ ++ txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu]; ++ } ++ /* ++ * need to propagate to shm location to be in sync since ucode/hw won't ++ * do this ++ */ ++ brcms_b_write_shm(wlc_hw, M_FIFOSIZE0, ++ wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]); ++ brcms_b_write_shm(wlc_hw, M_FIFOSIZE1, ++ wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]); ++ brcms_b_write_shm(wlc_hw, M_FIFOSIZE2, ++ ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw-> ++ xmtfifo_sz[TX_AC_BK_FIFO])); ++ brcms_b_write_shm(wlc_hw, M_FIFOSIZE3, ++ ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw-> ++ xmtfifo_sz[TX_BCMC_FIFO])); ++} ++ ++/* This function is used for changing the tsf frac register ++ * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz ++ * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz ++ * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz ++ * HTPHY Formula is 2^26/freq(MHz) e.g. ++ * For spuron2 - 126MHz -> 2^26/126 = 532610.0 ++ * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082 ++ * For spuron: 123MHz -> 2^26/123 = 545600.5 ++ * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341 ++ * For spur off: 120MHz -> 2^26/120 = 559240.5 ++ * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889 ++ */ ++ ++void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ ++ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || ++ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) { ++ if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ ++ W_REG(®s->tsf_clk_frac_l, 0x2082); ++ W_REG(®s->tsf_clk_frac_h, 0x8); ++ } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */ ++ W_REG(®s->tsf_clk_frac_l, 0x5341); ++ W_REG(®s->tsf_clk_frac_h, 0x8); ++ } else { /* 120Mhz */ ++ W_REG(®s->tsf_clk_frac_l, 0x8889); ++ W_REG(®s->tsf_clk_frac_h, 0x8); ++ } ++ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { ++ if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */ ++ W_REG(®s->tsf_clk_frac_l, 0x7CE0); ++ W_REG(®s->tsf_clk_frac_h, 0xC); ++ } else { /* 80Mhz */ ++ W_REG(®s->tsf_clk_frac_l, 0xCCCD); ++ W_REG(®s->tsf_clk_frac_h, 0xC); ++ } ++ } ++} ++ ++/* Initialize GPIOs that are controlled by D11 core */ ++static void brcms_c_gpio_init(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs; ++ u32 gc, gm; ++ ++ regs = wlc_hw->regs; ++ ++ /* use GPIO select 0 to get all gpio signals from the gpio out reg */ ++ brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0); ++ ++ /* ++ * Common GPIO setup: ++ * G0 = LED 0 = WLAN Activity ++ * G1 = LED 1 = WLAN 2.4 GHz Radio State ++ * G2 = LED 2 = WLAN 5 GHz Radio State ++ * G4 = radio disable input (HI enabled, LO disabled) ++ */ ++ ++ gc = gm = 0; ++ ++ /* Allocate GPIOs for mimo antenna diversity feature */ ++ if (wlc_hw->antsel_type == ANTSEL_2x3) { ++ /* Enable antenna diversity, use 2x3 mode */ ++ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, ++ MHF3_ANTSEL_EN, BRCM_BAND_ALL); ++ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, ++ MHF3_ANTSEL_MODE, BRCM_BAND_ALL); ++ ++ /* init superswitch control */ ++ wlc_phy_antsel_init(wlc_hw->band->pi, false); ++ ++ } else if (wlc_hw->antsel_type == ANTSEL_2x4) { ++ gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13); ++ /* ++ * The board itself is powered by these GPIOs ++ * (when not sending pattern) so set them high ++ */ ++ OR_REG(®s->psm_gpio_oe, ++ (BOARD_GPIO_12 | BOARD_GPIO_13)); ++ OR_REG(®s->psm_gpio_out, ++ (BOARD_GPIO_12 | BOARD_GPIO_13)); ++ ++ /* Enable antenna diversity, use 2x4 mode */ ++ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, ++ MHF3_ANTSEL_EN, BRCM_BAND_ALL); ++ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0, ++ BRCM_BAND_ALL); ++ ++ /* Configure the desired clock to be 4Mhz */ ++ brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV, ++ ANTSEL_CLKDIV_4MHZ); ++ } ++ ++ /* ++ * gpio 9 controls the PA. ucode is responsible ++ * for wiggling out and oe ++ */ ++ if (wlc_hw->boardflags & BFL_PACTRL) ++ gm |= gc |= BOARD_GPIO_PACTRL; ++ ++ /* apply to gpiocontrol register */ ++ ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY); ++} ++ ++static void brcms_ucode_write(struct brcms_hardware *wlc_hw, ++ const __le32 ucode[], const size_t nbytes) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ uint i; ++ uint count; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ count = (nbytes / sizeof(u32)); ++ ++ W_REG(®s->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL)); ++ (void)R_REG(®s->objaddr); ++ for (i = 0; i < count; i++) ++ W_REG(®s->objdata, le32_to_cpu(ucode[i])); ++ ++} ++ ++static void brcms_ucode_download(struct brcms_hardware *wlc_hw) ++{ ++ struct brcms_c_info *wlc; ++ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; ++ ++ wlc = wlc_hw->wlc; ++ ++ if (wlc_hw->ucode_loaded) ++ return; ++ ++ if (D11REV_IS(wlc_hw->corerev, 23)) { ++ if (BRCMS_ISNPHY(wlc_hw->band)) { ++ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo, ++ ucode->bcm43xx_16_mimosz); ++ wlc_hw->ucode_loaded = true; ++ } else ++ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " ++ "corerev %d\n", ++ __func__, wlc_hw->unit, wlc_hw->corerev); ++ } else if (D11REV_IS(wlc_hw->corerev, 24)) { ++ if (BRCMS_ISLCNPHY(wlc_hw->band)) { ++ brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn, ++ ucode->bcm43xx_24_lcnsz); ++ wlc_hw->ucode_loaded = true; ++ } else { ++ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " ++ "corerev %d\n", ++ __func__, wlc_hw->unit, wlc_hw->corerev); ++ } ++ } ++} ++ ++void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant) ++{ ++ /* update sw state */ ++ wlc_hw->bmac_phytxant = phytxant; ++ ++ /* push to ucode if up */ ++ if (!wlc_hw->up) ++ return; ++ brcms_c_ucode_txant_set(wlc_hw); ++ ++} ++ ++u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw) ++{ ++ return (u16) wlc_hw->wlc->stf->txant; ++} ++ ++void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type) ++{ ++ wlc_hw->antsel_type = antsel_type; ++ ++ /* Update the antsel type for phy module to use */ ++ wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type); ++} ++ ++static void brcms_c_fatal_error(struct brcms_c_info *wlc) ++{ ++ wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n", ++ wlc->pub->unit); ++ brcms_init(wlc->wl); ++} ++ ++static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) ++{ ++ bool fatal = false; ++ uint unit; ++ uint intstatus, idx; ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ struct wiphy *wiphy = wlc_hw->wlc->wiphy; ++ ++ unit = wlc_hw->unit; ++ ++ for (idx = 0; idx < NFIFO; idx++) { ++ /* read intstatus register and ignore any non-error bits */ ++ intstatus = ++ R_REG(®s->intctrlregs[idx].intstatus) & I_ERRORS; ++ if (!intstatus) ++ continue; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n", ++ unit, idx, intstatus); ++ ++ if (intstatus & I_RO) { ++ wiphy_err(wiphy, "wl%d: fifo %d: receive fifo " ++ "overflow\n", unit, idx); ++ fatal = true; ++ } ++ ++ if (intstatus & I_PC) { ++ wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n", ++ unit, idx); ++ fatal = true; ++ } ++ ++ if (intstatus & I_PD) { ++ wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit, ++ idx); ++ fatal = true; ++ } ++ ++ if (intstatus & I_DE) { ++ wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol " ++ "error\n", unit, idx); ++ fatal = true; ++ } ++ ++ if (intstatus & I_RU) ++ wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor " ++ "underflow\n", idx, unit); ++ ++ if (intstatus & I_XU) { ++ wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo " ++ "underflow\n", idx, unit); ++ fatal = true; ++ } ++ ++ if (fatal) { ++ brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */ ++ break; ++ } else ++ W_REG(®s->intctrlregs[idx].intstatus, ++ intstatus); ++ } ++} ++ ++void brcms_c_intrson(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ wlc->macintmask = wlc->defmacintmask; ++ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); ++} ++ ++/* ++ * callback for siutils.c, which has only wlc handler, no wl they both check ++ * up, not only because there is no need to off/restore d11 interrupt but also ++ * because per-port code may require sync with valid interrupt. ++ */ ++static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc) ++{ ++ if (!wlc->hw->up) ++ return 0; ++ ++ return brcms_intrsoff(wlc->wl); ++} ++ ++static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask) ++{ ++ if (!wlc->hw->up) ++ return; ++ ++ brcms_intrsrestore(wlc->wl, macintmask); ++} ++ ++u32 brcms_c_intrsoff(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ u32 macintmask; ++ ++ if (!wlc_hw->clk) ++ return 0; ++ ++ macintmask = wlc->macintmask; /* isr can still happen */ ++ ++ W_REG(&wlc_hw->regs->macintmask, 0); ++ (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */ ++ udelay(1); /* ensure int line is no longer driven */ ++ wlc->macintmask = 0; ++ ++ /* return previous macintmask; resolve race between us and our isr */ ++ return wlc->macintstatus ? 0 : macintmask; ++} ++ ++void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ if (!wlc_hw->clk) ++ return; ++ ++ wlc->macintmask = macintmask; ++ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); ++} ++ ++static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw, ++ uint tx_fifo) ++{ ++ u8 fifo = 1 << tx_fifo; ++ ++ /* Two clients of this code, 11h Quiet period and scanning. */ ++ ++ /* only suspend if not already suspended */ ++ if ((wlc_hw->suspended_fifos & fifo) == fifo) ++ return; ++ ++ /* force the core awake only if not already */ ++ if (wlc_hw->suspended_fifos == 0) ++ brcms_c_ucode_wake_override_set(wlc_hw, ++ BRCMS_WAKE_OVERRIDE_TXFIFO); ++ ++ wlc_hw->suspended_fifos |= fifo; ++ ++ if (wlc_hw->di[tx_fifo]) { ++ /* ++ * Suspending AMPDU transmissions in the middle can cause ++ * underflow which may result in mismatch between ucode and ++ * driver so suspend the mac before suspending the FIFO ++ */ ++ if (BRCMS_PHY_11N_CAP(wlc_hw->band)) ++ brcms_c_suspend_mac_and_wait(wlc_hw->wlc); ++ ++ dma_txsuspend(wlc_hw->di[tx_fifo]); ++ ++ if (BRCMS_PHY_11N_CAP(wlc_hw->band)) ++ brcms_c_enable_mac(wlc_hw->wlc); ++ } ++} ++ ++static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, ++ uint tx_fifo) ++{ ++ /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case ++ * but need to be done here for PIO otherwise the watchdog will catch ++ * the inconsistency and fire ++ */ ++ /* Two clients of this code, 11h Quiet period and scanning. */ ++ if (wlc_hw->di[tx_fifo]) ++ dma_txresume(wlc_hw->di[tx_fifo]); ++ ++ /* allow core to sleep again */ ++ if (wlc_hw->suspended_fifos == 0) ++ return; ++ else { ++ wlc_hw->suspended_fifos &= ~(1 << tx_fifo); ++ if (wlc_hw->suspended_fifos == 0) ++ brcms_c_ucode_wake_override_clear(wlc_hw, ++ BRCMS_WAKE_OVERRIDE_TXFIFO); ++ } ++} ++ ++static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags) ++{ ++ static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; ++ ++ if (on) { ++ /* suspend tx fifos */ ++ brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO); ++ brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO); ++ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO); ++ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO); ++ ++ /* zero the address match register so we do not send ACKs */ ++ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ++ null_ether_addr); ++ } else { ++ /* resume tx fifos */ ++ brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO); ++ brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO); ++ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO); ++ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO); ++ ++ /* Restore address */ ++ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ++ wlc_hw->etheraddr); ++ } ++ ++ wlc_phy_mute_upd(wlc_hw->band->pi, on, flags); ++ ++ if (on) ++ brcms_c_ucode_mute_override_set(wlc_hw); ++ else ++ brcms_c_ucode_mute_override_clear(wlc_hw); ++} ++ ++/* ++ * Read and clear macintmask and macintstatus and intstatus registers. ++ * This routine should be called with interrupts off ++ * Return: ++ * -1 if brcms_deviceremoved(wlc) evaluates to true; ++ * 0 if the interrupt is not for us, or we are in some special cases; ++ * device interrupt status bits otherwise. ++ */ ++static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u32 macintstatus; ++ ++ /* macintstatus includes a DMA interrupt summary bit */ ++ macintstatus = R_REG(®s->macintstatus); ++ ++ BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit, ++ macintstatus); ++ ++ /* detect cardbus removed, in power down(suspend) and in reset */ ++ if (brcms_deviceremoved(wlc)) ++ return -1; ++ ++ /* brcms_deviceremoved() succeeds even when the core is still resetting, ++ * handle that case here. ++ */ ++ if (macintstatus == 0xffffffff) ++ return 0; ++ ++ /* defer unsolicited interrupts */ ++ macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask); ++ ++ /* if not for us */ ++ if (macintstatus == 0) ++ return 0; ++ ++ /* interrupts are already turned off for CFE build ++ * Caution: For CFE Turning off the interrupts again has some undesired ++ * consequences ++ */ ++ /* turn off the interrupts */ ++ W_REG(®s->macintmask, 0); ++ (void)R_REG(®s->macintmask); /* sync readback */ ++ wlc->macintmask = 0; ++ ++ /* clear device interrupts */ ++ W_REG(®s->macintstatus, macintstatus); ++ ++ /* MI_DMAINT is indication of non-zero intstatus */ ++ if (macintstatus & MI_DMAINT) ++ /* ++ * only fifo interrupt enabled is I_RI in ++ * RX_FIFO. If MI_DMAINT is set, assume it ++ * is set and clear the interrupt. ++ */ ++ W_REG(®s->intctrlregs[RX_FIFO].intstatus, ++ DEF_RXINTMASK); ++ ++ return macintstatus; ++} ++ ++/* Update wlc->macintstatus and wlc->intstatus[]. */ ++/* Return true if they are updated successfully. false otherwise */ ++bool brcms_c_intrsupd(struct brcms_c_info *wlc) ++{ ++ u32 macintstatus; ++ ++ /* read and clear macintstatus and intstatus registers */ ++ macintstatus = wlc_intstatus(wlc, false); ++ ++ /* device is removed */ ++ if (macintstatus == 0xffffffff) ++ return false; ++ ++ /* update interrupt status in software */ ++ wlc->macintstatus |= macintstatus; ++ ++ return true; ++} ++ ++/* ++ * First-level interrupt processing. ++ * Return true if this was our interrupt, false otherwise. ++ * *wantdpc will be set to true if further brcms_c_dpc() processing is required, ++ * false otherwise. ++ */ ++bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ u32 macintstatus; ++ ++ *wantdpc = false; ++ ++ if (!wlc_hw->up || !wlc->macintmask) ++ return false; ++ ++ /* read and clear macintstatus and intstatus registers */ ++ macintstatus = wlc_intstatus(wlc, true); ++ ++ if (macintstatus == 0xffffffff) ++ wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code" ++ " path\n"); ++ ++ /* it is not for us */ ++ if (macintstatus == 0) ++ return false; ++ ++ *wantdpc = true; ++ ++ /* save interrupt status bits */ ++ wlc->macintstatus = macintstatus; ++ ++ return true; ++ ++} ++ ++void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u32 mc, mi; ++ struct wiphy *wiphy = wlc->wiphy; ++ ++ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, ++ wlc_hw->band->bandunit); ++ ++ /* ++ * Track overlapping suspend requests ++ */ ++ wlc_hw->mac_suspend_depth++; ++ if (wlc_hw->mac_suspend_depth > 1) ++ return; ++ ++ /* force the core awake */ ++ brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND); ++ ++ mc = R_REG(®s->maccontrol); ++ ++ if (mc == 0xffffffff) { ++ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return; ++ } ++ WARN_ON(mc & MCTL_PSM_JMP_0); ++ WARN_ON(!(mc & MCTL_PSM_RUN)); ++ WARN_ON(!(mc & MCTL_EN_MAC)); ++ ++ mi = R_REG(®s->macintstatus); ++ if (mi == 0xffffffff) { ++ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return; ++ } ++ WARN_ON(mi & MI_MACSSPNDD); ++ ++ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0); ++ ++ SPINWAIT(!(R_REG(®s->macintstatus) & MI_MACSSPNDD), ++ BRCMS_MAX_MAC_SUSPEND); ++ ++ if (!(R_REG(®s->macintstatus) & MI_MACSSPNDD)) { ++ wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" ++ " and MI_MACSSPNDD is still not on.\n", ++ wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND); ++ wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " ++ "psm_brc 0x%04x\n", wlc_hw->unit, ++ R_REG(®s->psmdebug), ++ R_REG(®s->phydebug), ++ R_REG(®s->psm_brc)); ++ } ++ ++ mc = R_REG(®s->maccontrol); ++ if (mc == 0xffffffff) { ++ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return; ++ } ++ WARN_ON(mc & MCTL_PSM_JMP_0); ++ WARN_ON(!(mc & MCTL_PSM_RUN)); ++ WARN_ON(mc & MCTL_EN_MAC); ++} ++ ++void brcms_c_enable_mac(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u32 mc, mi; ++ ++ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, ++ wlc->band->bandunit); ++ ++ /* ++ * Track overlapping suspend requests ++ */ ++ wlc_hw->mac_suspend_depth--; ++ if (wlc_hw->mac_suspend_depth > 0) ++ return; ++ ++ mc = R_REG(®s->maccontrol); ++ WARN_ON(mc & MCTL_PSM_JMP_0); ++ WARN_ON(mc & MCTL_EN_MAC); ++ WARN_ON(!(mc & MCTL_PSM_RUN)); ++ ++ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC); ++ W_REG(®s->macintstatus, MI_MACSSPNDD); ++ ++ mc = R_REG(®s->maccontrol); ++ WARN_ON(mc & MCTL_PSM_JMP_0); ++ WARN_ON(!(mc & MCTL_EN_MAC)); ++ WARN_ON(!(mc & MCTL_PSM_RUN)); ++ ++ mi = R_REG(®s->macintstatus); ++ WARN_ON(mi & MI_MACSSPNDD); ++ ++ brcms_c_ucode_wake_override_clear(wlc_hw, ++ BRCMS_WAKE_OVERRIDE_MACSUSPEND); ++} ++ ++void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode) ++{ ++ wlc_hw->hw_stf_ss_opmode = stf_mode; ++ ++ if (wlc_hw->clk) ++ brcms_upd_ofdm_pctl1_table(wlc_hw); ++} ++ ++static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) ++{ ++ struct d11regs __iomem *regs; ++ u32 w, val; ++ struct wiphy *wiphy = wlc_hw->wlc->wiphy; ++ ++ BCMMSG(wiphy, "wl%d\n", wlc_hw->unit); ++ ++ regs = wlc_hw->regs; ++ ++ /* Validate dchip register access */ ++ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ w = R_REG(®s->objdata); ++ ++ /* Can we write and read back a 32bit register? */ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ W_REG(®s->objdata, (u32) 0xaa5555aa); ++ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ val = R_REG(®s->objdata); ++ if (val != (u32) 0xaa5555aa) { ++ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " ++ "expected 0xaa5555aa\n", wlc_hw->unit, val); ++ return false; ++ } ++ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ W_REG(®s->objdata, (u32) 0x55aaaa55); ++ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ val = R_REG(®s->objdata); ++ if (val != (u32) 0x55aaaa55) { ++ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " ++ "expected 0x55aaaa55\n", wlc_hw->unit, val); ++ return false; ++ } ++ ++ W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); ++ (void)R_REG(®s->objaddr); ++ W_REG(®s->objdata, w); ++ ++ /* clear CFPStart */ ++ W_REG(®s->tsf_cfpstart, 0); ++ ++ w = R_REG(®s->maccontrol); ++ if ((w != (MCTL_IHR_EN | MCTL_WAKE)) && ++ (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) { ++ wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = " ++ "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w, ++ (MCTL_IHR_EN | MCTL_WAKE), ++ (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE)); ++ return false; ++ } ++ ++ return true; ++} ++ ++#define PHYPLL_WAIT_US 100000 ++ ++void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) ++{ ++ struct d11regs __iomem *regs; ++ u32 tmp; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ tmp = 0; ++ regs = wlc_hw->regs; ++ ++ if (on) { ++ if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) { ++ OR_REG(®s->clk_ctl_st, ++ (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL | ++ CCS_ERSRC_REQ_PHYPLL)); ++ SPINWAIT((R_REG(®s->clk_ctl_st) & ++ (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT), ++ PHYPLL_WAIT_US); ++ ++ tmp = R_REG(®s->clk_ctl_st); ++ if ((tmp & (CCS_ERSRC_AVAIL_HT)) != ++ (CCS_ERSRC_AVAIL_HT)) ++ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY" ++ " PLL failed\n", __func__); ++ } else { ++ OR_REG(®s->clk_ctl_st, ++ (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL)); ++ SPINWAIT((R_REG(®s->clk_ctl_st) & ++ (CCS_ERSRC_AVAIL_D11PLL | ++ CCS_ERSRC_AVAIL_PHYPLL)) != ++ (CCS_ERSRC_AVAIL_D11PLL | ++ CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US); ++ ++ tmp = R_REG(®s->clk_ctl_st); ++ if ((tmp & ++ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) ++ != ++ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) ++ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on " ++ "PHY PLL failed\n", __func__); ++ } ++ } else { ++ /* ++ * Since the PLL may be shared, other cores can still ++ * be requesting it; so we'll deassert the request but ++ * not wait for status to comply. ++ */ ++ AND_REG(®s->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL); ++ tmp = R_REG(®s->clk_ctl_st); ++ } ++} ++ ++static void brcms_c_coredisable(struct brcms_hardware *wlc_hw) ++{ ++ bool dev_gone; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ dev_gone = brcms_deviceremoved(wlc_hw->wlc); ++ ++ if (dev_gone) ++ return; ++ ++ if (wlc_hw->noreset) ++ return; ++ ++ /* radio off */ ++ wlc_phy_switch_radio(wlc_hw->band->pi, OFF); ++ ++ /* turn off analog core */ ++ wlc_phy_anacore(wlc_hw->band->pi, OFF); ++ ++ /* turn off PHYPLL to save power */ ++ brcms_b_core_phypll_ctl(wlc_hw, false); ++ ++ wlc_hw->clk = false; ++ ai_core_disable(wlc_hw->sih, 0); ++ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); ++} ++ ++static void brcms_c_flushqueues(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ uint i; ++ ++ /* free any posted tx packets */ ++ for (i = 0; i < NFIFO; i++) ++ if (wlc_hw->di[i]) { ++ dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL); ++ wlc->core->txpktpend[i] = 0; ++ BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i); ++ } ++ ++ /* free any posted rx packets */ ++ dma_rxreclaim(wlc_hw->di[RX_FIFO]); ++} ++ ++static u16 ++brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; ++ u16 __iomem *objdata_hi = objdata_lo + 1; ++ u16 v; ++ ++ W_REG(®s->objaddr, sel | (offset >> 2)); ++ (void)R_REG(®s->objaddr); ++ if (offset & 2) ++ v = R_REG(objdata_hi); ++ else ++ v = R_REG(objdata_lo); ++ ++ return v; ++} ++ ++static void ++brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v, ++ u32 sel) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; ++ u16 __iomem *objdata_hi = objdata_lo + 1; ++ ++ W_REG(®s->objaddr, sel | (offset >> 2)); ++ (void)R_REG(®s->objaddr); ++ if (offset & 2) ++ W_REG(objdata_hi, v); ++ else ++ W_REG(objdata_lo, v); ++} ++ ++/* ++ * Read a single u16 from shared memory. ++ * SHM 'offset' needs to be an even address ++ */ ++u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset) ++{ ++ return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL); ++} ++ ++/* ++ * Write a single u16 to shared memory. ++ * SHM 'offset' needs to be an even address ++ */ ++void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v) ++{ ++ brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL); ++} ++ ++/* ++ * Copy a buffer to shared memory of specified type . ++ * SHM 'offset' needs to be an even address and ++ * Buffer length 'len' must be an even number of bytes ++ * 'sel' selects the type of memory ++ */ ++void ++brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset, ++ const void *buf, int len, u32 sel) ++{ ++ u16 v; ++ const u8 *p = (const u8 *)buf; ++ int i; ++ ++ if (len <= 0 || (offset & 1) || (len & 1)) ++ return; ++ ++ for (i = 0; i < len; i += 2) { ++ v = p[i] | (p[i + 1] << 8); ++ brcms_b_write_objmem(wlc_hw, offset + i, v, sel); ++ } ++} ++ ++/* ++ * Copy a piece of shared memory of specified type to a buffer . ++ * SHM 'offset' needs to be an even address and ++ * Buffer length 'len' must be an even number of bytes ++ * 'sel' selects the type of memory ++ */ ++void ++brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf, ++ int len, u32 sel) ++{ ++ u16 v; ++ u8 *p = (u8 *) buf; ++ int i; ++ ++ if (len <= 0 || (offset & 1) || (len & 1)) ++ return; ++ ++ for (i = 0; i < len; i += 2) { ++ v = brcms_b_read_objmem(wlc_hw, offset + i, sel); ++ p[i] = v & 0xFF; ++ p[i + 1] = (v >> 8) & 0xFF; ++ } ++} ++ ++/* Copy a buffer to shared memory. ++ * SHM 'offset' needs to be an even address and ++ * Buffer length 'len' must be an even number of bytes ++ */ ++static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset, ++ const void *buf, int len) ++{ ++ brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL); ++} ++ ++static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, ++ u16 SRL, u16 LRL) ++{ ++ wlc_hw->SRL = SRL; ++ wlc_hw->LRL = LRL; ++ ++ /* write retry limit to SCR, shouldn't need to suspend */ ++ if (wlc_hw->up) { ++ W_REG(&wlc_hw->regs->objaddr, ++ OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); ++ (void)R_REG(&wlc_hw->regs->objaddr); ++ W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL); ++ W_REG(&wlc_hw->regs->objaddr, ++ OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); ++ (void)R_REG(&wlc_hw->regs->objaddr); ++ W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL); ++ } ++} ++ ++static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit) ++{ ++ if (set) { ++ if (mboolisset(wlc_hw->pllreq, req_bit)) ++ return; ++ ++ mboolset(wlc_hw->pllreq, req_bit); ++ ++ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { ++ if (!wlc_hw->sbclk) ++ brcms_b_xtal(wlc_hw, ON); ++ } ++ } else { ++ if (!mboolisset(wlc_hw->pllreq, req_bit)) ++ return; ++ ++ mboolclr(wlc_hw->pllreq, req_bit); ++ ++ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { ++ if (wlc_hw->sbclk) ++ brcms_b_xtal(wlc_hw, OFF); ++ } ++ } ++} ++ ++static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail) ++{ ++ wlc_hw->antsel_avail = antsel_avail; ++} ++ ++/* ++ * conditions under which the PM bit should be set in outgoing frames ++ * and STAY_AWAKE is meaningful ++ */ ++static bool brcms_c_ps_allowed(struct brcms_c_info *wlc) ++{ ++ struct brcms_bss_cfg *cfg = wlc->bsscfg; ++ ++ /* disallow PS when one of the following global conditions meets */ ++ if (!wlc->pub->associated) ++ return false; ++ ++ /* disallow PS when one of these meets when not scanning */ ++ if (wlc->monitor) ++ return false; ++ ++ if (cfg->associated) { ++ /* ++ * disallow PS when one of the following ++ * bsscfg specific conditions meets ++ */ ++ if (!cfg->BSS) ++ return false; ++ ++ return false; ++ } ++ ++ return true; ++} ++ ++static void brcms_c_statsupd(struct brcms_c_info *wlc) ++{ ++ int i; ++ struct macstat macstats; ++#ifdef BCMDBG ++ u16 delta; ++ u16 rxf0ovfl; ++ u16 txfunfl[NFIFO]; ++#endif /* BCMDBG */ ++ ++ /* if driver down, make no sense to update stats */ ++ if (!wlc->pub->up) ++ return; ++ ++#ifdef BCMDBG ++ /* save last rx fifo 0 overflow count */ ++ rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl; ++ ++ /* save last tx fifo underflow count */ ++ for (i = 0; i < NFIFO; i++) ++ txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i]; ++#endif /* BCMDBG */ ++ ++ /* Read mac stats from contiguous shared memory */ ++ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats, ++ sizeof(struct macstat), OBJADDR_SHM_SEL); ++ ++#ifdef BCMDBG ++ /* check for rx fifo 0 overflow */ ++ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); ++ if (delta) ++ wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n", ++ wlc->pub->unit, delta); ++ ++ /* check for tx fifo underflows */ ++ for (i = 0; i < NFIFO; i++) { ++ delta = ++ (u16) (wlc->core->macstat_snapshot->txfunfl[i] - ++ txfunfl[i]); ++ if (delta) ++ wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!" ++ "\n", wlc->pub->unit, delta, i); ++ } ++#endif /* BCMDBG */ ++ ++ /* merge counters from dma module */ ++ for (i = 0; i < NFIFO; i++) { ++ if (wlc->hw->di[i]) ++ dma_counterreset(wlc->hw->di[i]); ++ } ++} ++ ++static void brcms_b_reset(struct brcms_hardware *wlc_hw) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ /* reset the core */ ++ if (!brcms_deviceremoved(wlc_hw->wlc)) ++ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); ++ ++ /* purge the dma rings */ ++ brcms_c_flushqueues(wlc_hw->wlc); ++} ++ ++void brcms_c_reset(struct brcms_c_info *wlc) ++{ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ /* slurp up hw mac counters before core reset */ ++ brcms_c_statsupd(wlc); ++ ++ /* reset our snapshot of macstat counters */ ++ memset((char *)wlc->core->macstat_snapshot, 0, ++ sizeof(struct macstat)); ++ ++ brcms_b_reset(wlc->hw); ++} ++ ++/* Return the channel the driver should initialize during brcms_c_init. ++ * the channel may have to be changed from the currently configured channel ++ * if other configurations are in conflict (bandlocked, 11n mode disabled, ++ * invalid channel for current country, etc.) ++ */ ++static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc) ++{ ++ u16 chanspec = ++ 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | ++ WL_CHANSPEC_BAND_2G; ++ ++ return chanspec; ++} ++ ++void brcms_c_init_scb(struct scb *scb) ++{ ++ int i; ++ ++ memset(scb, 0, sizeof(struct scb)); ++ scb->flags = SCB_WMECAP | SCB_HTCAP; ++ for (i = 0; i < NUMPRIO; i++) { ++ scb->seqnum[i] = 0; ++ scb->seqctl[i] = 0xFFFF; ++ } ++ ++ scb->seqctl_nonqos = 0xFFFF; ++ scb->magic = SCB_MAGIC; ++} ++ ++/* d11 core init ++ * reset PSM ++ * download ucode/PCM ++ * let ucode run to suspended ++ * download ucode inits ++ * config other core registers ++ * init dma ++ */ ++static void brcms_b_coreinit(struct brcms_c_info *wlc) ++{ ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs; ++ u32 sflags; ++ uint bcnint_us; ++ uint i = 0; ++ bool fifosz_fixup = false; ++ int err = 0; ++ u16 buf[NFIFO]; ++ struct wiphy *wiphy = wlc->wiphy; ++ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; ++ ++ regs = wlc_hw->regs; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ /* reset PSM */ ++ brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE)); ++ ++ brcms_ucode_download(wlc_hw); ++ /* ++ * FIFOSZ fixup. driver wants to controls the fifo allocation. ++ */ ++ fifosz_fixup = true; ++ ++ /* let the PSM run to the suspended state, set mode to BSS STA */ ++ W_REG(®s->macintstatus, -1); ++ brcms_b_mctrl(wlc_hw, ~0, ++ (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE)); ++ ++ /* wait for ucode to self-suspend after auto-init */ ++ SPINWAIT(((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0), ++ 1000 * 1000); ++ if ((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0) ++ wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-" ++ "suspend!\n", wlc_hw->unit); ++ ++ brcms_c_gpio_init(wlc); ++ ++ sflags = ai_core_sflags(wlc_hw->sih, 0, 0); ++ ++ if (D11REV_IS(wlc_hw->corerev, 23)) { ++ if (BRCMS_ISNPHY(wlc_hw->band)) ++ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16); ++ else ++ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" ++ " %d\n", __func__, wlc_hw->unit, ++ wlc_hw->corerev); ++ } else if (D11REV_IS(wlc_hw->corerev, 24)) { ++ if (BRCMS_ISLCNPHY(wlc_hw->band)) ++ brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24); ++ else ++ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" ++ " %d\n", __func__, wlc_hw->unit, ++ wlc_hw->corerev); ++ } else { ++ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", ++ __func__, wlc_hw->unit, wlc_hw->corerev); ++ } ++ ++ /* For old ucode, txfifo sizes needs to be modified(increased) */ ++ if (fifosz_fixup == true) ++ brcms_b_corerev_fifofixup(wlc_hw); ++ ++ /* check txfifo allocations match between ucode and driver */ ++ buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0); ++ if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) { ++ i = TX_AC_BE_FIFO; ++ err = -1; ++ } ++ buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1); ++ if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) { ++ i = TX_AC_VI_FIFO; ++ err = -1; ++ } ++ buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2); ++ buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff; ++ buf[TX_AC_BK_FIFO] &= 0xff; ++ if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) { ++ i = TX_AC_BK_FIFO; ++ err = -1; ++ } ++ if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) { ++ i = TX_AC_VO_FIFO; ++ err = -1; ++ } ++ buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3); ++ buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff; ++ buf[TX_BCMC_FIFO] &= 0xff; ++ if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) { ++ i = TX_BCMC_FIFO; ++ err = -1; ++ } ++ if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) { ++ i = TX_ATIM_FIFO; ++ err = -1; ++ } ++ if (err != 0) ++ wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d" ++ " driver size %d index %d\n", buf[i], ++ wlc_hw->xmtfifo_sz[i], i); ++ ++ /* make sure we can still talk to the mac */ ++ WARN_ON(R_REG(®s->maccontrol) == 0xffffffff); ++ ++ /* band-specific inits done by wlc_bsinit() */ ++ ++ /* Set up frame burst size and antenna swap threshold init values */ ++ brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST); ++ brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT); ++ ++ /* enable one rx interrupt per received frame */ ++ W_REG(®s->intrcvlazy[0], (1 << IRL_FC_SHIFT)); ++ ++ /* set the station mode (BSS STA) */ ++ brcms_b_mctrl(wlc_hw, ++ (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP), ++ (MCTL_INFRA | MCTL_DISCARD_PMQ)); ++ ++ /* set up Beacon interval */ ++ bcnint_us = 0x8000 << 10; ++ W_REG(®s->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT)); ++ W_REG(®s->tsf_cfpstart, bcnint_us); ++ W_REG(®s->macintstatus, MI_GP1); ++ ++ /* write interrupt mask */ ++ W_REG(®s->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK); ++ ++ /* allow the MAC to control the PHY clock (dynamic on/off) */ ++ brcms_b_macphyclk_set(wlc_hw, ON); ++ ++ /* program dynamic clock control fast powerup delay register */ ++ wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih); ++ W_REG(®s->scc_fastpwrup_dly, wlc->fastpwrup_dly); ++ ++ /* tell the ucode the corerev */ ++ brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev); ++ ++ /* tell the ucode MAC capabilities */ ++ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L, ++ (u16) (wlc_hw->machwcap & 0xffff)); ++ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H, ++ (u16) ((wlc_hw-> ++ machwcap >> 16) & 0xffff)); ++ ++ /* write retry limits to SCR, this done after PSM init */ ++ W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); ++ (void)R_REG(®s->objaddr); ++ W_REG(®s->objdata, wlc_hw->SRL); ++ W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); ++ (void)R_REG(®s->objaddr); ++ W_REG(®s->objdata, wlc_hw->LRL); ++ ++ /* write rate fallback retry limits */ ++ brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL); ++ brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL); ++ ++ AND_REG(®s->ifs_ctl, 0x0FFF); ++ W_REG(®s->ifs_aifsn, EDCF_AIFSN_MIN); ++ ++ /* init the tx dma engines */ ++ for (i = 0; i < NFIFO; i++) { ++ if (wlc_hw->di[i]) ++ dma_txinit(wlc_hw->di[i]); ++ } ++ ++ /* init the rx dma engine(s) and post receive buffers */ ++ dma_rxinit(wlc_hw->di[RX_FIFO]); ++ dma_rxfill(wlc_hw->di[RX_FIFO]); ++} ++ ++void ++static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec, ++ bool mute) { ++ u32 macintmask; ++ bool fastclk; ++ struct brcms_c_info *wlc = wlc_hw->wlc; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ /* request FAST clock if not on */ ++ fastclk = wlc_hw->forcefastclk; ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ /* disable interrupts */ ++ macintmask = brcms_intrsoff(wlc->wl); ++ ++ /* set up the specified band and chanspec */ ++ brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec)); ++ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); ++ ++ /* do one-time phy inits and calibration */ ++ wlc_phy_cal_init(wlc_hw->band->pi); ++ ++ /* core-specific initialization */ ++ brcms_b_coreinit(wlc); ++ ++ /* suspend the tx fifos and mute the phy for preism cac time */ ++ if (mute) ++ brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM); ++ ++ /* band-specific inits */ ++ brcms_b_bsinit(wlc, chanspec); ++ ++ /* restore macintmask */ ++ brcms_intrsrestore(wlc->wl, macintmask); ++ ++ /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac ++ * is suspended and brcms_c_enable_mac() will clear this override bit. ++ */ ++ mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND); ++ ++ /* ++ * initialize mac_suspend_depth to 1 to match ucode ++ * initial suspended state ++ */ ++ wlc_hw->mac_suspend_depth = 1; ++ ++ /* restore the clk */ ++ if (!fastclk) ++ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); ++} ++ ++static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, ++ u16 chanspec) ++{ ++ /* Save our copy of the chanspec */ ++ wlc->chanspec = chanspec; ++ ++ /* Set the chanspec and power limits for this locale */ ++ brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX); ++ ++ if (wlc->stf->ss_algosel_auto) ++ brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel, ++ chanspec); ++ ++ brcms_c_stf_ss_update(wlc, wlc->band); ++} ++ ++static void ++brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs) ++{ ++ brcms_c_rateset_default(rs, NULL, wlc->band->phytype, ++ wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL, ++ (bool) (wlc->pub->_n_enab & SUPPORT_11N), ++ brcms_chspec_bw(wlc->default_bss->chanspec), ++ wlc->stf->txstreams); ++} ++ ++/* derive wlc->band->basic_rate[] table from 'rateset' */ ++static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc, ++ struct brcms_c_rateset *rateset) ++{ ++ u8 rate; ++ u8 mandatory; ++ u8 cck_basic = 0; ++ u8 ofdm_basic = 0; ++ u8 *br = wlc->band->basic_rate; ++ uint i; ++ ++ /* incoming rates are in 500kbps units as in 802.11 Supported Rates */ ++ memset(br, 0, BRCM_MAXRATE + 1); ++ ++ /* For each basic rate in the rates list, make an entry in the ++ * best basic lookup. ++ */ ++ for (i = 0; i < rateset->count; i++) { ++ /* only make an entry for a basic rate */ ++ if (!(rateset->rates[i] & BRCMS_RATE_FLAG)) ++ continue; ++ ++ /* mask off basic bit */ ++ rate = (rateset->rates[i] & BRCMS_RATE_MASK); ++ ++ if (rate > BRCM_MAXRATE) { ++ wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: " ++ "invalid rate 0x%X in rate set\n", ++ rateset->rates[i]); ++ continue; ++ } ++ ++ br[rate] = rate; ++ } ++ ++ /* The rate lookup table now has non-zero entries for each ++ * basic rate, equal to the basic rate: br[basicN] = basicN ++ * ++ * To look up the best basic rate corresponding to any ++ * particular rate, code can use the basic_rate table ++ * like this ++ * ++ * basic_rate = wlc->band->basic_rate[tx_rate] ++ * ++ * Make sure there is a best basic rate entry for ++ * every rate by walking up the table from low rates ++ * to high, filling in holes in the lookup table ++ */ ++ ++ for (i = 0; i < wlc->band->hw_rateset.count; i++) { ++ rate = wlc->band->hw_rateset.rates[i]; ++ ++ if (br[rate] != 0) { ++ /* This rate is a basic rate. ++ * Keep track of the best basic rate so far by ++ * modulation type. ++ */ ++ if (is_ofdm_rate(rate)) ++ ofdm_basic = rate; ++ else ++ cck_basic = rate; ++ ++ continue; ++ } ++ ++ /* This rate is not a basic rate so figure out the ++ * best basic rate less than this rate and fill in ++ * the hole in the table ++ */ ++ ++ br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic; ++ ++ if (br[rate] != 0) ++ continue; ++ ++ if (is_ofdm_rate(rate)) { ++ /* ++ * In 11g and 11a, the OFDM mandatory rates ++ * are 6, 12, and 24 Mbps ++ */ ++ if (rate >= BRCM_RATE_24M) ++ mandatory = BRCM_RATE_24M; ++ else if (rate >= BRCM_RATE_12M) ++ mandatory = BRCM_RATE_12M; ++ else ++ mandatory = BRCM_RATE_6M; ++ } else { ++ /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */ ++ mandatory = rate; ++ } ++ ++ br[rate] = mandatory; ++ } ++} ++ ++static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, ++ u16 chanspec) ++{ ++ struct brcms_c_rateset default_rateset; ++ uint parkband; ++ uint i, band_order[2]; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ /* ++ * We might have been bandlocked during down and the chip ++ * power-cycled (hibernate). Figure out the right band to park on ++ */ ++ if (wlc->bandlocked || wlc->pub->_nbands == 1) { ++ /* updated in brcms_c_bandlock() */ ++ parkband = wlc->band->bandunit; ++ band_order[0] = band_order[1] = parkband; ++ } else { ++ /* park on the band of the specified chanspec */ ++ parkband = chspec_bandunit(chanspec); ++ ++ /* order so that parkband initialize last */ ++ band_order[0] = parkband ^ 1; ++ band_order[1] = parkband; ++ } ++ ++ /* make each band operational, software state init */ ++ for (i = 0; i < wlc->pub->_nbands; i++) { ++ uint j = band_order[i]; ++ ++ wlc->band = wlc->bandstate[j]; ++ ++ brcms_default_rateset(wlc, &default_rateset); ++ ++ /* fill in hw_rate */ ++ brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset, ++ false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, ++ (bool) (wlc->pub->_n_enab & SUPPORT_11N)); ++ ++ /* init basic rate lookup */ ++ brcms_c_rate_lookup_init(wlc, &default_rateset); ++ } ++ ++ /* sync up phy/radio chanspec */ ++ brcms_c_set_phy_chanspec(wlc, chanspec); ++} ++ ++static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc) ++{ ++ if (wlc->bcnmisc_monitor) ++ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC); ++ else ++ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0); ++} ++ ++void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) ++{ ++ wlc->bcnmisc_monitor = promisc; ++ brcms_c_mac_bcn_promisc(wlc); ++} ++ ++/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */ ++static void brcms_c_mac_promisc(struct brcms_c_info *wlc) ++{ ++ u32 promisc_bits = 0; ++ ++ /* ++ * promiscuous mode just sets MCTL_PROMISC ++ * Note: APs get all BSS traffic without the need to set ++ * the MCTL_PROMISC bit since all BSS data traffic is ++ * directed at the AP ++ */ ++ if (wlc->pub->promisc) ++ promisc_bits |= MCTL_PROMISC; ++ ++ /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL ++ * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is ++ * handled in brcms_c_mac_bcn_promisc() ++ */ ++ if (wlc->monitor) ++ promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL; ++ ++ brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits); ++} ++ ++/* ++ * ucode, hwmac update ++ * Channel dependent updates for ucode and hw ++ */ ++static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc) ++{ ++ /* enable or disable any active IBSSs depending on whether or not ++ * we are on the home channel ++ */ ++ if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) { ++ if (wlc->pub->associated) { ++ /* ++ * BMAC_NOTE: This is something that should be fixed ++ * in ucode inits. I think that the ucode inits set ++ * up the bcn templates and shm values with a bogus ++ * beacon. This should not be done in the inits. If ++ * ucode needs to set up a beacon for testing, the ++ * test routines should write it down, not expect the ++ * inits to populate a bogus beacon. ++ */ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) ++ brcms_b_write_shm(wlc->hw, ++ M_BCN_TXTSF_OFFSET, 0); ++ } ++ } else { ++ /* disable an active IBSS if we are not on the home channel */ ++ } ++ ++ /* update the various promisc bits */ ++ brcms_c_mac_bcn_promisc(wlc); ++ brcms_c_mac_promisc(wlc); ++} ++ ++static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate, ++ u8 basic_rate) ++{ ++ u8 phy_rate, index; ++ u8 basic_phy_rate, basic_index; ++ u16 dir_table, basic_table; ++ u16 basic_ptr; ++ ++ /* Shared memory address for the table we are reading */ ++ dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B; ++ ++ /* Shared memory address for the table we are writing */ ++ basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B; ++ ++ /* ++ * for a given rate, the LS-nibble of the PLCP SIGNAL field is ++ * the index into the rate table. ++ */ ++ phy_rate = rate_info[rate] & BRCMS_RATE_MASK; ++ basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK; ++ index = phy_rate & 0xf; ++ basic_index = basic_phy_rate & 0xf; ++ ++ /* Find the SHM pointer to the ACK rate entry by looking in the ++ * Direct-map Table ++ */ ++ basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2)); ++ ++ /* Update the SHM BSS-basic-rate-set mapping table with the pointer ++ * to the correct basic rate for the given incoming rate ++ */ ++ brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr); ++} ++ ++static const struct brcms_c_rateset * ++brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc) ++{ ++ const struct brcms_c_rateset *rs_dflt; ++ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) { ++ if (wlc->band->bandtype == BRCM_BAND_5G) ++ rs_dflt = &ofdm_mimo_rates; ++ else ++ rs_dflt = &cck_ofdm_mimo_rates; ++ } else if (wlc->band->gmode) ++ rs_dflt = &cck_ofdm_rates; ++ else ++ rs_dflt = &cck_rates; ++ ++ return rs_dflt; ++} ++ ++static void brcms_c_set_ratetable(struct brcms_c_info *wlc) ++{ ++ const struct brcms_c_rateset *rs_dflt; ++ struct brcms_c_rateset rs; ++ u8 rate, basic_rate; ++ uint i; ++ ++ rs_dflt = brcms_c_rateset_get_hwrs(wlc); ++ ++ brcms_c_rateset_copy(rs_dflt, &rs); ++ brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); ++ ++ /* walk the phy rate table and update SHM basic rate lookup table */ ++ for (i = 0; i < rs.count; i++) { ++ rate = rs.rates[i] & BRCMS_RATE_MASK; ++ ++ /* for a given rate brcms_basic_rate returns the rate at ++ * which a response ACK/CTS should be sent. ++ */ ++ basic_rate = brcms_basic_rate(wlc, rate); ++ if (basic_rate == 0) ++ /* This should only happen if we are using a ++ * restricted rateset. ++ */ ++ basic_rate = rs.rates[0] & BRCMS_RATE_MASK; ++ ++ brcms_c_write_rate_shm(wlc, rate, basic_rate); ++ } ++} ++ ++/* band-specific init */ ++static void brcms_c_bsinit(struct brcms_c_info *wlc) ++{ ++ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", ++ wlc->pub->unit, wlc->band->bandunit); ++ ++ /* write ucode ACK/CTS rate table */ ++ brcms_c_set_ratetable(wlc); ++ ++ /* update some band specific mac configuration */ ++ brcms_c_ucode_mac_upd(wlc); ++ ++ /* init antenna selection */ ++ brcms_c_antsel_init(wlc->asi); ++ ++} ++ ++/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */ ++static int ++brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM, ++ bool writeToShm) ++{ ++ int idle_busy_ratio_x_16 = 0; ++ uint offset = ++ isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM : ++ M_TX_IDLE_BUSY_RATIO_X_16_CCK; ++ if (duty_cycle > 100 || duty_cycle < 0) { ++ wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n", ++ wlc->pub->unit); ++ return -EINVAL; ++ } ++ if (duty_cycle) ++ idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle; ++ /* Only write to shared memory when wl is up */ ++ if (writeToShm) ++ brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16); ++ ++ if (isOFDM) ++ wlc->tx_duty_cycle_ofdm = (u16) duty_cycle; ++ else ++ wlc->tx_duty_cycle_cck = (u16) duty_cycle; ++ ++ return 0; ++} ++ ++/* ++ * Initialize the base precedence map for dequeueing ++ * from txq based on WME settings ++ */ ++static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc) ++{ ++ wlc->tx_prec_map = BRCMS_PREC_BMP_ALL; ++ memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); ++ ++ wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK; ++ wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE; ++ wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI; ++ wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO; ++} ++ ++static void ++brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc, ++ struct brcms_txq_info *qi, bool on, int prio) ++{ ++ /* transmit flowcontrol is not yet implemented */ ++} ++ ++static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc) ++{ ++ struct brcms_txq_info *qi; ++ ++ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) { ++ if (qi->stopped) { ++ brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO); ++ qi->stopped = 0; ++ } ++ } ++} ++ ++/* push sw hps and wake state through hardware */ ++static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) ++{ ++ u32 v1, v2; ++ bool hps; ++ bool awake_before; ++ ++ hps = brcms_c_ps_allowed(wlc); ++ ++ BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps); ++ ++ v1 = R_REG(&wlc->regs->maccontrol); ++ v2 = MCTL_WAKE; ++ if (hps) ++ v2 |= MCTL_HPS; ++ ++ brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2); ++ ++ awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0)); ++ ++ if (!awake_before) ++ brcms_b_wait_for_wake(wlc->hw); ++} ++ ++/* ++ * Write this BSS config's MAC address to core. ++ * Updates RXE match engine. ++ */ ++static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg) ++{ ++ int err = 0; ++ struct brcms_c_info *wlc = bsscfg->wlc; ++ ++ /* enter the MAC addr into the RXE match registers */ ++ brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr); ++ ++ brcms_c_ampdu_macaddr_upd(wlc); ++ ++ return err; ++} ++ ++/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl). ++ * Updates RXE match engine. ++ */ ++static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg) ++{ ++ /* we need to update BSSID in RXE match registers */ ++ brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID); ++} ++ ++static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot) ++{ ++ wlc_hw->shortslot = shortslot; ++ ++ if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) { ++ brcms_c_suspend_mac_and_wait(wlc_hw->wlc); ++ brcms_b_update_slot_timing(wlc_hw, shortslot); ++ brcms_c_enable_mac(wlc_hw->wlc); ++ } ++} ++ ++/* ++ * Suspend the the MAC and update the slot timing ++ * for standard 11b/g (20us slots) or shortslot 11g (9us slots). ++ */ ++static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot) ++{ ++ /* use the override if it is set */ ++ if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO) ++ shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON); ++ ++ if (wlc->shortslot == shortslot) ++ return; ++ ++ wlc->shortslot = shortslot; ++ ++ brcms_b_set_shortslot(wlc->hw, shortslot); ++} ++ ++static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec) ++{ ++ if (wlc->home_chanspec != chanspec) { ++ wlc->home_chanspec = chanspec; ++ ++ if (wlc->bsscfg->associated) ++ wlc->bsscfg->current_bss->chanspec = chanspec; ++ } ++} ++ ++void ++brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec, ++ bool mute, struct txpwr_limits *txpwr) ++{ ++ uint bandunit; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec); ++ ++ wlc_hw->chanspec = chanspec; ++ ++ /* Switch bands if necessary */ ++ if (wlc_hw->_nbands > 1) { ++ bandunit = chspec_bandunit(chanspec); ++ if (wlc_hw->band->bandunit != bandunit) { ++ /* brcms_b_setband disables other bandunit, ++ * use light band switch if not up yet ++ */ ++ if (wlc_hw->up) { ++ wlc_phy_chanspec_radio_set(wlc_hw-> ++ bandstate[bandunit]-> ++ pi, chanspec); ++ brcms_b_setband(wlc_hw, bandunit, chanspec); ++ } else { ++ brcms_c_setxband(wlc_hw, bandunit); ++ } ++ } ++ } ++ ++ wlc_phy_initcal_enable(wlc_hw->band->pi, !mute); ++ ++ if (!wlc_hw->up) { ++ if (wlc_hw->clk) ++ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, ++ chanspec); ++ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); ++ } else { ++ wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec); ++ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec); ++ ++ /* Update muting of the channel */ ++ brcms_b_mute(wlc_hw, mute, 0); ++ } ++} ++ ++/* switch to and initialize new band */ ++static void brcms_c_setband(struct brcms_c_info *wlc, ++ uint bandunit) ++{ ++ wlc->band = wlc->bandstate[bandunit]; ++ ++ if (!wlc->pub->up) ++ return; ++ ++ /* wait for at least one beacon before entering sleeping state */ ++ brcms_c_set_ps_ctrl(wlc); ++ ++ /* band-specific initializations */ ++ brcms_c_bsinit(wlc); ++} ++ ++static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec) ++{ ++ uint bandunit; ++ bool switchband = false; ++ u16 old_chanspec = wlc->chanspec; ++ ++ if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n", ++ wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); ++ return; ++ } ++ ++ /* Switch bands if necessary */ ++ if (wlc->pub->_nbands > 1) { ++ bandunit = chspec_bandunit(chanspec); ++ if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) { ++ switchband = true; ++ if (wlc->bandlocked) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d " ++ "band is locked!\n", ++ wlc->pub->unit, __func__, ++ CHSPEC_CHANNEL(chanspec)); ++ return; ++ } ++ /* ++ * should the setband call come after the ++ * brcms_b_chanspec() ? if the setband updates ++ * (brcms_c_bsinit) use low level calls to inspect and ++ * set state, the state inspected may be from the wrong ++ * band, or the following brcms_b_set_chanspec() may ++ * undo the work. ++ */ ++ brcms_c_setband(wlc, bandunit); ++ } ++ } ++ ++ /* sync up phy/radio chanspec */ ++ brcms_c_set_phy_chanspec(wlc, chanspec); ++ ++ /* init antenna selection */ ++ if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) { ++ brcms_c_antsel_init(wlc->asi); ++ ++ /* Fix the hardware rateset based on bw. ++ * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz ++ */ ++ brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset, ++ wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0); ++ } ++ ++ /* update some mac configuration since chanspec changed */ ++ brcms_c_ucode_mac_upd(wlc); ++} ++ ++/* ++ * This function changes the phytxctl for beacon based on current ++ * beacon ratespec AND txant setting as per this table: ++ * ratespec CCK ant = wlc->stf->txant ++ * OFDM ant = 3 ++ */ ++void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, ++ u32 bcn_rspec) ++{ ++ u16 phyctl; ++ u16 phytxant = wlc->stf->phytxant; ++ u16 mask = PHY_TXC_ANT_MASK; ++ ++ /* for non-siso rates or default setting, use the available chains */ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) ++ phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec); ++ ++ phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD); ++ phyctl = (phyctl & ~mask) | phytxant; ++ brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl); ++} ++ ++/* ++ * centralized protection config change function to simplify debugging, no ++ * consistency checking this should be called only on changes to avoid overhead ++ * in periodic function ++ */ ++void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val) ++{ ++ BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val); ++ ++ switch (idx) { ++ case BRCMS_PROT_G_SPEC: ++ wlc->protection->_g = (bool) val; ++ break; ++ case BRCMS_PROT_G_OVR: ++ wlc->protection->g_override = (s8) val; ++ break; ++ case BRCMS_PROT_G_USER: ++ wlc->protection->gmode_user = (u8) val; ++ break; ++ case BRCMS_PROT_OVERLAP: ++ wlc->protection->overlap = (s8) val; ++ break; ++ case BRCMS_PROT_N_USER: ++ wlc->protection->nmode_user = (s8) val; ++ break; ++ case BRCMS_PROT_N_CFG: ++ wlc->protection->n_cfg = (s8) val; ++ break; ++ case BRCMS_PROT_N_CFG_OVR: ++ wlc->protection->n_cfg_override = (s8) val; ++ break; ++ case BRCMS_PROT_N_NONGF: ++ wlc->protection->nongf = (bool) val; ++ break; ++ case BRCMS_PROT_N_NONGF_OVR: ++ wlc->protection->nongf_override = (s8) val; ++ break; ++ case BRCMS_PROT_N_PAM_OVR: ++ wlc->protection->n_pam_override = (s8) val; ++ break; ++ case BRCMS_PROT_N_OBSS: ++ wlc->protection->n_obss = (bool) val; ++ break; ++ ++ default: ++ break; ++ } ++ ++} ++ ++static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val) ++{ ++ if (wlc->pub->up) { ++ brcms_c_update_beacon(wlc); ++ brcms_c_update_probe_resp(wlc, true); ++ } ++} ++ ++static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val) ++{ ++ wlc->stf->ldpc = val; ++ ++ if (wlc->pub->up) { ++ brcms_c_update_beacon(wlc); ++ brcms_c_update_probe_resp(wlc, true); ++ wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false)); ++ } ++} ++ ++void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, ++ const struct ieee80211_tx_queue_params *params, ++ bool suspend) ++{ ++ int i; ++ struct shm_acparams acp_shm; ++ u16 *shm_entry; ++ ++ /* Only apply params if the core is out of reset and has clocks */ ++ if (!wlc->clk) { ++ wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit, ++ __func__); ++ return; ++ } ++ ++ memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); ++ /* fill in shm ac params struct */ ++ acp_shm.txop = params->txop; ++ /* convert from units of 32us to us for ucode */ ++ wlc->edcf_txop[aci & 0x3] = acp_shm.txop = ++ EDCF_TXOP2USEC(acp_shm.txop); ++ acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK); ++ ++ if (aci == AC_VI && acp_shm.txop == 0 ++ && acp_shm.aifs < EDCF_AIFSN_MAX) ++ acp_shm.aifs++; ++ ++ if (acp_shm.aifs < EDCF_AIFSN_MIN ++ || acp_shm.aifs > EDCF_AIFSN_MAX) { ++ wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad " ++ "aifs %d\n", wlc->pub->unit, acp_shm.aifs); ++ } else { ++ acp_shm.cwmin = params->cw_min; ++ acp_shm.cwmax = params->cw_max; ++ acp_shm.cwcur = acp_shm.cwmin; ++ acp_shm.bslots = ++ R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur; ++ acp_shm.reggap = acp_shm.bslots + acp_shm.aifs; ++ /* Indicate the new params to the ucode */ ++ acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO + ++ wme_ac2fifo[aci] * ++ M_EDCF_QLEN + ++ M_EDCF_STATUS_OFF)); ++ acp_shm.status |= WME_STATUS_NEWAC; ++ ++ /* Fill in shm acparam table */ ++ shm_entry = (u16 *) &acp_shm; ++ for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2) ++ brcms_b_write_shm(wlc->hw, ++ M_EDCF_QINFO + ++ wme_ac2fifo[aci] * M_EDCF_QLEN + i, ++ *shm_entry++); ++ } ++ ++ if (suspend) { ++ brcms_c_suspend_mac_and_wait(wlc); ++ brcms_c_enable_mac(wlc); ++ } ++} ++ ++void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) ++{ ++ u16 aci; ++ int i_ac; ++ struct ieee80211_tx_queue_params txq_pars; ++ static const struct edcf_acparam default_edcf_acparams[] = { ++ {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA}, ++ {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA}, ++ {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA}, ++ {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA} ++ }; /* ucode needs these parameters during its initialization */ ++ const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0]; ++ ++ for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) { ++ /* find out which ac this set of params applies to */ ++ aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; ++ ++ /* fill in shm ac params struct */ ++ txq_pars.txop = edcf_acp->TXOP; ++ txq_pars.aifs = edcf_acp->ACI; ++ ++ /* CWmin = 2^(ECWmin) - 1 */ ++ txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK); ++ /* CWmax = 2^(ECWmax) - 1 */ ++ txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK) ++ >> EDCF_ECWMAX_SHIFT); ++ brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend); ++ } ++ ++ if (suspend) { ++ brcms_c_suspend_mac_and_wait(wlc); ++ brcms_c_enable_mac(wlc); ++ } ++} ++ ++/* maintain LED behavior in down state */ ++static void brcms_c_down_led_upd(struct brcms_c_info *wlc) ++{ ++ /* ++ * maintain LEDs while in down state, turn on sbclk if ++ * not available yet. Turn on sbclk if necessary ++ */ ++ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP); ++ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP); ++} ++ ++static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc) ++{ ++ /* Don't start the timer if HWRADIO feature is disabled */ ++ if (wlc->radio_monitor) ++ return; ++ ++ wlc->radio_monitor = true; ++ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON); ++ brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true); ++} ++ ++static void brcms_c_radio_disable(struct brcms_c_info *wlc) ++{ ++ if (!wlc->pub->up) { ++ brcms_c_down_led_upd(wlc); ++ return; ++ } ++ ++ brcms_c_radio_monitor_start(wlc); ++ brcms_down(wlc->wl); ++} ++ ++static void brcms_c_radio_enable(struct brcms_c_info *wlc) ++{ ++ if (wlc->pub->up) ++ return; ++ ++ if (brcms_deviceremoved(wlc)) ++ return; ++ ++ brcms_up(wlc->wl); ++} ++ ++static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc) ++{ ++ if (!wlc->radio_monitor) ++ return true; ++ ++ wlc->radio_monitor = false; ++ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON); ++ return brcms_del_timer(wlc->radio_timer); ++} ++ ++/* read hwdisable state and propagate to wlc flag */ ++static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc) ++{ ++ if (wlc->pub->hw_off) ++ return; ++ ++ if (brcms_b_radio_read_hwdisabled(wlc->hw)) ++ mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); ++ else ++ mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); ++} ++ ++/* ++ * centralized radio disable/enable function, ++ * invoke radio enable/disable after updating hwradio status ++ */ ++static void brcms_c_radio_upd(struct brcms_c_info *wlc) ++{ ++ if (wlc->pub->radio_disabled) ++ brcms_c_radio_disable(wlc); ++ else ++ brcms_c_radio_enable(wlc); ++} ++ ++/* update hwradio status and return it */ ++bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc) ++{ ++ brcms_c_radio_hwdisable_upd(wlc); ++ ++ return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ? ++ true : false; ++} ++ ++/* periodical query hw radio button while driver is "down" */ ++static void brcms_c_radio_timer(void *arg) ++{ ++ struct brcms_c_info *wlc = (struct brcms_c_info *) arg; ++ ++ if (brcms_deviceremoved(wlc)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return; ++ } ++ ++ /* cap mpc off count */ ++ if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT) ++ wlc->mpc_offcnt++; ++ ++ brcms_c_radio_hwdisable_upd(wlc); ++ brcms_c_radio_upd(wlc); ++} ++ ++/* common low-level watchdog code */ ++static void brcms_b_watchdog(void *arg) ++{ ++ struct brcms_c_info *wlc = (struct brcms_c_info *) arg; ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ if (!wlc_hw->up) ++ return; ++ ++ /* increment second count */ ++ wlc_hw->now++; ++ ++ /* Check for FIFO error interrupts */ ++ brcms_b_fifoerrors(wlc_hw); ++ ++ /* make sure RX dma has buffers */ ++ dma_rxfill(wlc->hw->di[RX_FIFO]); ++ ++ wlc_phy_watchdog(wlc_hw->band->pi); ++} ++ ++static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc) ++{ ++ bool mpc_radio, radio_state; ++ ++ /* ++ * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled ++ * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio ++ * monitor also when WL_RADIO_MPC_DISABLE is the only reason that ++ * the radio is going down. ++ */ ++ if (!wlc->mpc) { ++ if (!wlc->pub->radio_disabled) ++ return; ++ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); ++ brcms_c_radio_upd(wlc); ++ if (!wlc->pub->radio_disabled) ++ brcms_c_radio_monitor_stop(wlc); ++ return; ++ } ++ ++ /* ++ * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in ++ * wlc->pub->radio_disabled to go ON, always call radio_upd ++ * synchronously to go OFF, postpone radio_upd to later when ++ * context is safe(e.g. watchdog) ++ */ ++ radio_state = ++ (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF : ++ ON); ++ mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON; ++ ++ if (radio_state == ON && mpc_radio == OFF) ++ wlc->mpc_delay_off = wlc->mpc_dlycnt; ++ else if (radio_state == OFF && mpc_radio == ON) { ++ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); ++ brcms_c_radio_upd(wlc); ++ if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD) ++ wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT; ++ else ++ wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; ++ } ++ /* ++ * Below logic is meant to capture the transition from mpc off ++ * to mpc on for reasons other than wlc->mpc_delay_off keeping ++ * the mpc off. In that case reset wlc->mpc_delay_off to ++ * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off ++ */ ++ if ((wlc->prev_non_delay_mpc == false) && ++ (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off) ++ wlc->mpc_delay_off = wlc->mpc_dlycnt; ++ ++ wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc); ++} ++ ++/* common watchdog code */ ++static void brcms_c_watchdog(void *arg) ++{ ++ struct brcms_c_info *wlc = (struct brcms_c_info *) arg; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ if (!wlc->pub->up) ++ return; ++ ++ if (brcms_deviceremoved(wlc)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return; ++ } ++ ++ /* increment second count */ ++ wlc->pub->now++; ++ ++ /* delay radio disable */ ++ if (wlc->mpc_delay_off) { ++ if (--wlc->mpc_delay_off == 0) { ++ mboolset(wlc->pub->radio_disabled, ++ WL_RADIO_MPC_DISABLE); ++ if (wlc->mpc && brcms_c_ismpc(wlc)) ++ wlc->mpc_offcnt = 0; ++ } ++ } ++ ++ /* mpc sync */ ++ brcms_c_radio_mpc_upd(wlc); ++ /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */ ++ brcms_c_radio_hwdisable_upd(wlc); ++ brcms_c_radio_upd(wlc); ++ /* if radio is disable, driver may be down, quit here */ ++ if (wlc->pub->radio_disabled) ++ return; ++ ++ brcms_b_watchdog(wlc); ++ ++ /* ++ * occasionally sample mac stat counters to ++ * detect 16-bit counter wrap ++ */ ++ if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0) ++ brcms_c_statsupd(wlc); ++ ++ if (BRCMS_ISNPHY(wlc->band) && ++ ((wlc->pub->now - wlc->tempsense_lasttime) >= ++ BRCMS_TEMPSENSE_PERIOD)) { ++ wlc->tempsense_lasttime = wlc->pub->now; ++ brcms_c_tempsense_upd(wlc); ++ } ++} ++ ++static void brcms_c_watchdog_by_timer(void *arg) ++{ ++ brcms_c_watchdog(arg); ++} ++ ++static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) ++{ ++ wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer, ++ wlc, "watchdog"); ++ if (!wlc->wdtimer) { ++ wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer " ++ "failed\n", unit); ++ goto fail; ++ } ++ ++ wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer, ++ wlc, "radio"); ++ if (!wlc->radio_timer) { ++ wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer " ++ "failed\n", unit); ++ goto fail; ++ } ++ ++ return true; ++ ++ fail: ++ return false; ++} ++ ++/* ++ * Initialize brcms_c_info default values ... ++ * may get overrides later in this function ++ */ ++static void brcms_c_info_init(struct brcms_c_info *wlc, int unit) ++{ ++ int i; ++ ++ /* Save our copy of the chanspec */ ++ wlc->chanspec = ch20mhz_chspec(1); ++ ++ /* various 802.11g modes */ ++ wlc->shortslot = false; ++ wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO; ++ ++ brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO); ++ brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false); ++ ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR, ++ BRCMS_PROTECTION_AUTO); ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF); ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR, ++ BRCMS_PROTECTION_AUTO); ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false); ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO); ++ ++ brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP, ++ BRCMS_PROTECTION_CTL_OVERLAP); ++ ++ /* 802.11g draft 4.0 NonERP elt advertisement */ ++ wlc->include_legacy_erp = true; ++ ++ wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF; ++ wlc->stf->txant = ANT_TX_DEF; ++ ++ wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT; ++ ++ wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN; ++ for (i = 0; i < NFIFO; i++) ++ wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN; ++ wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN; ++ ++ /* default rate fallback retry limits */ ++ wlc->SFBL = RETRY_SHORT_FB; ++ wlc->LFBL = RETRY_LONG_FB; ++ ++ /* default mac retry limits */ ++ wlc->SRL = RETRY_SHORT_DEF; ++ wlc->LRL = RETRY_LONG_DEF; ++ ++ /* WME QoS mode is Auto by default */ ++ wlc->pub->_ampdu = AMPDU_AGG_HOST; ++ wlc->pub->bcmerror = 0; ++ ++ /* initialize mpc delay */ ++ wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; ++} ++ ++static uint brcms_c_attach_module(struct brcms_c_info *wlc) ++{ ++ uint err = 0; ++ uint unit; ++ unit = wlc->pub->unit; ++ ++ wlc->asi = brcms_c_antsel_attach(wlc); ++ if (wlc->asi == NULL) { ++ wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach " ++ "failed\n", unit); ++ err = 44; ++ goto fail; ++ } ++ ++ wlc->ampdu = brcms_c_ampdu_attach(wlc); ++ if (wlc->ampdu == NULL) { ++ wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach " ++ "failed\n", unit); ++ err = 50; ++ goto fail; ++ } ++ ++ if ((brcms_c_stf_attach(wlc) != 0)) { ++ wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach " ++ "failed\n", unit); ++ err = 68; ++ goto fail; ++ } ++ fail: ++ return err; ++} ++ ++struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc) ++{ ++ return wlc->pub; ++} ++ ++/* low level attach ++ * run backplane attach, init nvram ++ * run phy attach ++ * initialize software state for each core and band ++ * put the whole chip in reset(driver down state), no clock ++ */ ++static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, ++ uint unit, bool piomode, void __iomem *regsva, ++ struct pci_dev *btparam) ++{ ++ struct brcms_hardware *wlc_hw; ++ struct d11regs __iomem *regs; ++ char *macaddr = NULL; ++ uint err = 0; ++ uint j; ++ bool wme = false; ++ struct shared_phy_params sha_params; ++ struct wiphy *wiphy = wlc->wiphy; ++ ++ BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor, ++ device); ++ ++ wme = true; ++ ++ wlc_hw = wlc->hw; ++ wlc_hw->wlc = wlc; ++ wlc_hw->unit = unit; ++ wlc_hw->band = wlc_hw->bandstate[0]; ++ wlc_hw->_piomode = piomode; ++ ++ /* populate struct brcms_hardware with default values */ ++ brcms_b_info_init(wlc_hw); ++ ++ /* ++ * Do the hardware portion of the attach. Also initialize software ++ * state that depends on the particular hardware we are running. ++ */ ++ wlc_hw->sih = ai_attach(regsva, btparam); ++ if (wlc_hw->sih == NULL) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n", ++ unit); ++ err = 11; ++ goto fail; ++ } ++ ++ /* verify again the device is supported */ ++ if (!brcms_c_chipmatch(vendor, device)) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " ++ "vendor/device (0x%x/0x%x)\n", ++ unit, vendor, device); ++ err = 12; ++ goto fail; ++ } ++ ++ wlc_hw->vendorid = vendor; ++ wlc_hw->deviceid = device; ++ ++ /* set bar0 window to point at D11 core */ ++ wlc_hw->regs = (struct d11regs __iomem *) ++ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); ++ wlc_hw->corerev = ai_corerev(wlc_hw->sih); ++ ++ regs = wlc_hw->regs; ++ ++ wlc->regs = wlc_hw->regs; ++ ++ /* validate chip, chiprev and corerev */ ++ if (!brcms_c_isgoodchip(wlc_hw)) { ++ err = 13; ++ goto fail; ++ } ++ ++ /* initialize power control registers */ ++ ai_clkctl_init(wlc_hw->sih); ++ ++ /* request fastclock and force fastclock for the rest of attach ++ * bring the d11 core out of reset. ++ * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk ++ * is still false; But it will be called again inside wlc_corereset, ++ * after d11 is out of reset. ++ */ ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); ++ ++ if (!brcms_b_validate_chip_access(wlc_hw)) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access " ++ "failed\n", unit); ++ err = 14; ++ goto fail; ++ } ++ ++ /* get the board rev, used just below */ ++ j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV); ++ /* promote srom boardrev of 0xFF to 1 */ ++ if (j == BOARDREV_PROMOTABLE) ++ j = BOARDREV_PROMOTED; ++ wlc_hw->boardrev = (u16) j; ++ if (!brcms_c_validboardtype(wlc_hw)) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom " ++ "board type (0x%x)" " or revision level (0x%x)\n", ++ unit, wlc_hw->sih->boardtype, wlc_hw->boardrev); ++ err = 15; ++ goto fail; ++ } ++ wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV); ++ wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih, ++ BRCMS_SROM_BOARDFLAGS); ++ wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih, ++ BRCMS_SROM_BOARDFLAGS2); ++ ++ if (wlc_hw->boardflags & BFL_NOPLLDOWN) ++ brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED); ++ ++ /* check device id(srom, nvram etc.) to set bands */ ++ if (wlc_hw->deviceid == BCM43224_D11N_ID || ++ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) ++ /* Dualband boards */ ++ wlc_hw->_nbands = 2; ++ else ++ wlc_hw->_nbands = 1; ++ ++ if ((wlc_hw->sih->chip == BCM43225_CHIP_ID)) ++ wlc_hw->_nbands = 1; ++ ++ /* BMAC_NOTE: remove init of pub values when brcms_c_attach() ++ * unconditionally does the init of these values ++ */ ++ wlc->vendorid = wlc_hw->vendorid; ++ wlc->deviceid = wlc_hw->deviceid; ++ wlc->pub->sih = wlc_hw->sih; ++ wlc->pub->corerev = wlc_hw->corerev; ++ wlc->pub->sromrev = wlc_hw->sromrev; ++ wlc->pub->boardrev = wlc_hw->boardrev; ++ wlc->pub->boardflags = wlc_hw->boardflags; ++ wlc->pub->boardflags2 = wlc_hw->boardflags2; ++ wlc->pub->_nbands = wlc_hw->_nbands; ++ ++ wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc); ++ ++ if (wlc_hw->physhim == NULL) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach " ++ "failed\n", unit); ++ err = 25; ++ goto fail; ++ } ++ ++ /* pass all the parameters to wlc_phy_shared_attach in one struct */ ++ sha_params.sih = wlc_hw->sih; ++ sha_params.physhim = wlc_hw->physhim; ++ sha_params.unit = unit; ++ sha_params.corerev = wlc_hw->corerev; ++ sha_params.vid = wlc_hw->vendorid; ++ sha_params.did = wlc_hw->deviceid; ++ sha_params.chip = wlc_hw->sih->chip; ++ sha_params.chiprev = wlc_hw->sih->chiprev; ++ sha_params.chippkg = wlc_hw->sih->chippkg; ++ sha_params.sromrev = wlc_hw->sromrev; ++ sha_params.boardtype = wlc_hw->sih->boardtype; ++ sha_params.boardrev = wlc_hw->boardrev; ++ sha_params.boardvendor = wlc_hw->sih->boardvendor; ++ sha_params.boardflags = wlc_hw->boardflags; ++ sha_params.boardflags2 = wlc_hw->boardflags2; ++ sha_params.buscorerev = wlc_hw->sih->buscorerev; ++ ++ /* alloc and save pointer to shared phy state area */ ++ wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params); ++ if (!wlc_hw->phy_sh) { ++ err = 16; ++ goto fail; ++ } ++ ++ /* initialize software state for each core and band */ ++ for (j = 0; j < wlc_hw->_nbands; j++) { ++ /* ++ * band0 is always 2.4Ghz ++ * band1, if present, is 5Ghz ++ */ ++ ++ brcms_c_setxband(wlc_hw, j); ++ ++ wlc_hw->band->bandunit = j; ++ wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; ++ wlc->band->bandunit = j; ++ wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; ++ wlc->core->coreidx = ai_coreidx(wlc_hw->sih); ++ ++ wlc_hw->machwcap = R_REG(®s->machwcap); ++ wlc_hw->machwcap_backup = wlc_hw->machwcap; ++ ++ /* init tx fifo size */ ++ wlc_hw->xmtfifo_sz = ++ xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; ++ ++ /* Get a phy for this band */ ++ wlc_hw->band->pi = ++ wlc_phy_attach(wlc_hw->phy_sh, regs, ++ wlc_hw->band->bandtype, ++ wlc->wiphy); ++ if (wlc_hw->band->pi == NULL) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_" ++ "attach failed\n", unit); ++ err = 17; ++ goto fail; ++ } ++ ++ wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap); ++ ++ wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype, ++ &wlc_hw->band->phyrev, ++ &wlc_hw->band->radioid, ++ &wlc_hw->band->radiorev); ++ wlc_hw->band->abgphy_encore = ++ wlc_phy_get_encore(wlc_hw->band->pi); ++ wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi); ++ wlc_hw->band->core_flags = ++ wlc_phy_get_coreflags(wlc_hw->band->pi); ++ ++ /* verify good phy_type & supported phy revision */ ++ if (BRCMS_ISNPHY(wlc_hw->band)) { ++ if (NCONF_HAS(wlc_hw->band->phyrev)) ++ goto good_phy; ++ else ++ goto bad_phy; ++ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { ++ if (LCNCONF_HAS(wlc_hw->band->phyrev)) ++ goto good_phy; ++ else ++ goto bad_phy; ++ } else { ++ bad_phy: ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported " ++ "phy type/rev (%d/%d)\n", unit, ++ wlc_hw->band->phytype, wlc_hw->band->phyrev); ++ err = 18; ++ goto fail; ++ } ++ ++ good_phy: ++ /* ++ * BMAC_NOTE: wlc->band->pi should not be set below and should ++ * be done in the high level attach. However we can not make ++ * that change until all low level access is changed to ++ * wlc_hw->band->pi. Instead do the wlc->band->pi init below, ++ * keeping wlc_hw->band->pi as well for incremental update of ++ * low level fns, and cut over low only init when all fns ++ * updated. ++ */ ++ wlc->band->pi = wlc_hw->band->pi; ++ wlc->band->phytype = wlc_hw->band->phytype; ++ wlc->band->phyrev = wlc_hw->band->phyrev; ++ wlc->band->radioid = wlc_hw->band->radioid; ++ wlc->band->radiorev = wlc_hw->band->radiorev; ++ ++ /* default contention windows size limits */ ++ wlc_hw->band->CWmin = APHY_CWMIN; ++ wlc_hw->band->CWmax = PHY_CWMAX; ++ ++ if (!brcms_b_attach_dmapio(wlc, j, wme)) { ++ err = 19; ++ goto fail; ++ } ++ } ++ ++ /* disable core to match driver "down" state */ ++ brcms_c_coredisable(wlc_hw); ++ ++ /* Match driver "down" state */ ++ ai_pci_down(wlc_hw->sih); ++ ++ /* register sb interrupt callback functions */ ++ ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff, ++ (void *)brcms_c_wlintrsrestore, NULL, wlc); ++ ++ /* turn off pll and xtal to match driver "down" state */ ++ brcms_b_xtal(wlc_hw, OFF); ++ ++ /* ******************************************************************* ++ * The hardware is in the DOWN state at this point. D11 core ++ * or cores are in reset with clocks off, and the board PLLs ++ * are off if possible. ++ * ++ * Beyond this point, wlc->sbclk == false and chip registers ++ * should not be touched. ++ ********************************************************************* ++ */ ++ ++ /* init etheraddr state variables */ ++ macaddr = brcms_c_get_macaddr(wlc_hw); ++ if (macaddr == NULL) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n", ++ unit); ++ err = 21; ++ goto fail; ++ } ++ if (!mac_pton(macaddr, wlc_hw->etheraddr) || ++ is_broadcast_ether_addr(wlc_hw->etheraddr) || ++ is_zero_ether_addr(wlc_hw->etheraddr)) { ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n", ++ unit, macaddr); ++ err = 22; ++ goto fail; ++ } ++ ++ BCMMSG(wlc->wiphy, ++ "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", ++ wlc_hw->deviceid, wlc_hw->_nbands, ++ wlc_hw->sih->boardtype, macaddr); ++ ++ return err; ++ ++ fail: ++ wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit, ++ err); ++ return err; ++} ++ ++static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc) ++{ ++ uint unit; ++ unit = wlc->pub->unit; ++ ++ if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) { ++ /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */ ++ wlc->band->antgain = 8; ++ } else if (wlc->band->antgain == -1) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" ++ " srom, using 2dB\n", unit, __func__); ++ wlc->band->antgain = 8; ++ } else { ++ s8 gain, fract; ++ /* Older sroms specified gain in whole dbm only. In order ++ * be able to specify qdbm granularity and remain backward ++ * compatible the whole dbms are now encoded in only ++ * low 6 bits and remaining qdbms are encoded in the hi 2 bits. ++ * 6 bit signed number ranges from -32 - 31. ++ * ++ * Examples: ++ * 0x1 = 1 db, ++ * 0xc1 = 1.75 db (1 + 3 quarters), ++ * 0x3f = -1 (-1 + 0 quarters), ++ * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm. ++ * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm. ++ */ ++ gain = wlc->band->antgain & 0x3f; ++ gain <<= 2; /* Sign extend */ ++ gain >>= 2; ++ fract = (wlc->band->antgain & 0xc0) >> 6; ++ wlc->band->antgain = 4 * gain + fract; ++ } ++} ++ ++static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) ++{ ++ int aa; ++ uint unit; ++ int bandtype; ++ struct si_pub *sih = wlc->hw->sih; ++ ++ unit = wlc->pub->unit; ++ bandtype = wlc->band->bandtype; ++ ++ /* get antennas available */ ++ if (bandtype == BRCM_BAND_5G) ++ aa = (s8) getintvar(sih, BRCMS_SROM_AA5G); ++ else ++ aa = (s8) getintvar(sih, BRCMS_SROM_AA2G); ++ ++ if ((aa < 1) || (aa > 15)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" ++ " srom (0x%x), using 3\n", unit, __func__, aa); ++ aa = 3; ++ } ++ ++ /* reset the defaults if we have a single antenna */ ++ if (aa == 1) { ++ wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0; ++ wlc->stf->txant = ANT_TX_FORCE_0; ++ } else if (aa == 2) { ++ wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1; ++ wlc->stf->txant = ANT_TX_FORCE_1; ++ } else { ++ } ++ ++ /* Compute Antenna Gain */ ++ if (bandtype == BRCM_BAND_5G) ++ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1); ++ else ++ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0); ++ ++ brcms_c_attach_antgain_init(wlc); ++ ++ return true; ++} ++ ++static void brcms_c_bss_default_init(struct brcms_c_info *wlc) ++{ ++ u16 chanspec; ++ struct brcms_band *band; ++ struct brcms_bss_info *bi = wlc->default_bss; ++ ++ /* init default and target BSS with some sane initial values */ ++ memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); ++ bi->beacon_period = BEACON_INTERVAL_DEFAULT; ++ ++ /* fill the default channel as the first valid channel ++ * starting from the 2G channels ++ */ ++ chanspec = ch20mhz_chspec(1); ++ wlc->home_chanspec = bi->chanspec = chanspec; ++ ++ /* find the band of our default channel */ ++ band = wlc->band; ++ if (wlc->pub->_nbands > 1 && ++ band->bandunit != chspec_bandunit(chanspec)) ++ band = wlc->bandstate[OTHERBANDUNIT(wlc)]; ++ ++ /* init bss rates to the band specific default rate set */ ++ brcms_c_rateset_default(&bi->rateset, NULL, band->phytype, ++ band->bandtype, false, BRCMS_RATE_MASK_FULL, ++ (bool) (wlc->pub->_n_enab & SUPPORT_11N), ++ brcms_chspec_bw(chanspec), wlc->stf->txstreams); ++ ++ if (wlc->pub->_n_enab & SUPPORT_11N) ++ bi->flags |= BRCMS_BSS_HT; ++} ++ ++static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc) ++{ ++ struct brcms_txq_info *qi, *p; ++ ++ qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC); ++ if (qi != NULL) { ++ /* ++ * Have enough room for control packets along with HI watermark ++ * Also, add room to txq for total psq packets if all the SCBs ++ * leave PS mode. The watermark for flowcontrol to OS packets ++ * will remain the same ++ */ ++ brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT, ++ 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT); ++ ++ /* add this queue to the the global list */ ++ p = wlc->tx_queues; ++ if (p == NULL) { ++ wlc->tx_queues = qi; ++ } else { ++ while (p->next != NULL) ++ p = p->next; ++ p->next = qi; ++ } ++ } ++ return qi; ++} ++ ++static void brcms_c_txq_free(struct brcms_c_info *wlc, ++ struct brcms_txq_info *qi) ++{ ++ struct brcms_txq_info *p; ++ ++ if (qi == NULL) ++ return; ++ ++ /* remove the queue from the linked list */ ++ p = wlc->tx_queues; ++ if (p == qi) ++ wlc->tx_queues = p->next; ++ else { ++ while (p != NULL && p->next != qi) ++ p = p->next; ++ if (p != NULL) ++ p->next = p->next->next; ++ } ++ ++ kfree(qi); ++} ++ ++static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap) ++{ ++ uint i; ++ struct brcms_band *band; ++ ++ for (i = 0; i < wlc->pub->_nbands; i++) { ++ band = wlc->bandstate[i]; ++ if (band->bandtype == BRCM_BAND_5G) { ++ if ((bwcap == BRCMS_N_BW_40ALL) ++ || (bwcap == BRCMS_N_BW_20IN2G_40IN5G)) ++ band->mimo_cap_40 = true; ++ else ++ band->mimo_cap_40 = false; ++ } else { ++ if (bwcap == BRCMS_N_BW_40ALL) ++ band->mimo_cap_40 = true; ++ else ++ band->mimo_cap_40 = false; ++ } ++ } ++} ++ ++static void brcms_c_timers_deinit(struct brcms_c_info *wlc) ++{ ++ /* free timer state */ ++ if (wlc->wdtimer) { ++ brcms_free_timer(wlc->wdtimer); ++ wlc->wdtimer = NULL; ++ } ++ if (wlc->radio_timer) { ++ brcms_free_timer(wlc->radio_timer); ++ wlc->radio_timer = NULL; ++ } ++} ++ ++static void brcms_c_detach_module(struct brcms_c_info *wlc) ++{ ++ if (wlc->asi) { ++ brcms_c_antsel_detach(wlc->asi); ++ wlc->asi = NULL; ++ } ++ ++ if (wlc->ampdu) { ++ brcms_c_ampdu_detach(wlc->ampdu); ++ wlc->ampdu = NULL; ++ } ++ ++ brcms_c_stf_detach(wlc); ++} ++ ++/* ++ * low level detach ++ */ ++static int brcms_b_detach(struct brcms_c_info *wlc) ++{ ++ uint i; ++ struct brcms_hw_band *band; ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ int callbacks; ++ ++ callbacks = 0; ++ ++ if (wlc_hw->sih) { ++ /* ++ * detach interrupt sync mechanism since interrupt is disabled ++ * and per-port interrupt object may has been freed. this must ++ * be done before sb core switch ++ */ ++ ai_deregister_intr_callback(wlc_hw->sih); ++ ai_pci_sleep(wlc_hw->sih); ++ } ++ ++ brcms_b_detach_dmapio(wlc_hw); ++ ++ band = wlc_hw->band; ++ for (i = 0; i < wlc_hw->_nbands; i++) { ++ if (band->pi) { ++ /* Detach this band's phy */ ++ wlc_phy_detach(band->pi); ++ band->pi = NULL; ++ } ++ band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)]; ++ } ++ ++ /* Free shared phy state */ ++ kfree(wlc_hw->phy_sh); ++ ++ wlc_phy_shim_detach(wlc_hw->physhim); ++ ++ if (wlc_hw->sih) { ++ ai_detach(wlc_hw->sih); ++ wlc_hw->sih = NULL; ++ } ++ ++ return callbacks; ++ ++} ++ ++/* ++ * Return a count of the number of driver callbacks still pending. ++ * ++ * General policy is that brcms_c_detach can only dealloc/free software states. ++ * It can NOT touch hardware registers since the d11core may be in reset and ++ * clock may not be available. ++ * One exception is sb register access, which is possible if crystal is turned ++ * on after "down" state, driver should avoid software timer with the exception ++ * of radio_monitor. ++ */ ++uint brcms_c_detach(struct brcms_c_info *wlc) ++{ ++ uint callbacks = 0; ++ ++ if (wlc == NULL) ++ return 0; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ callbacks += brcms_b_detach(wlc); ++ ++ /* delete software timers */ ++ if (!brcms_c_radio_monitor_stop(wlc)) ++ callbacks++; ++ ++ brcms_c_channel_mgr_detach(wlc->cmi); ++ ++ brcms_c_timers_deinit(wlc); ++ ++ brcms_c_detach_module(wlc); ++ ++ ++ while (wlc->tx_queues != NULL) ++ brcms_c_txq_free(wlc, wlc->tx_queues); ++ ++ brcms_c_detach_mfree(wlc); ++ return callbacks; ++} ++ ++/* update state that depends on the current value of "ap" */ ++static void brcms_c_ap_upd(struct brcms_c_info *wlc) ++{ ++ /* STA-BSS; short capable */ ++ wlc->PLCPHdr_override = BRCMS_PLCP_SHORT; ++ ++ /* fixup mpc */ ++ wlc->mpc = true; ++} ++ ++/* Initialize just the hardware when coming out of POR or S3/S5 system states */ ++static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) ++{ ++ if (wlc_hw->wlc->pub->hw_up) ++ return; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ /* ++ * Enable pll and xtal, initialize the power control registers, ++ * and force fastclock for the remainder of brcms_c_up(). ++ */ ++ brcms_b_xtal(wlc_hw, ON); ++ ai_clkctl_init(wlc_hw->sih); ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ ai_pci_fixcfg(wlc_hw->sih); ++ ++ /* ++ * AI chip doesn't restore bar0win2 on ++ * hibernation/resume, need sw fixup ++ */ ++ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || ++ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) ++ wlc_hw->regs = (struct d11regs __iomem *) ++ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); ++ ++ /* ++ * Inform phy that a POR reset has occurred so ++ * it does a complete phy init ++ */ ++ wlc_phy_por_inform(wlc_hw->band->pi); ++ ++ wlc_hw->ucode_loaded = false; ++ wlc_hw->wlc->pub->hw_up = true; ++ ++ if ((wlc_hw->boardflags & BFL_FEM) ++ && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) { ++ if (! ++ (wlc_hw->boardrev >= 0x1250 ++ && (wlc_hw->boardflags & BFL_FEM_BT))) ++ ai_epa_4313war(wlc_hw->sih); ++ } ++} ++ ++static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) ++{ ++ uint coremask; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ /* ++ * Enable pll and xtal, initialize the power control registers, ++ * and force fastclock for the remainder of brcms_c_up(). ++ */ ++ brcms_b_xtal(wlc_hw, ON); ++ ai_clkctl_init(wlc_hw->sih); ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ ++ /* ++ * Configure pci/pcmcia here instead of in brcms_c_attach() ++ * to allow mfg hotswap: down, hotswap (chip power cycle), up. ++ */ ++ coremask = (1 << wlc_hw->wlc->core->coreidx); ++ ++ ai_pci_setup(wlc_hw->sih, coremask); ++ ++ /* ++ * Need to read the hwradio status here to cover the case where the ++ * system is loaded with the hw radio disabled. We do not want to ++ * bring the driver up in this case. ++ */ ++ if (brcms_b_radio_read_hwdisabled(wlc_hw)) { ++ /* put SB PCI in down state again */ ++ ai_pci_down(wlc_hw->sih); ++ brcms_b_xtal(wlc_hw, OFF); ++ return -ENOMEDIUM; ++ } ++ ++ ai_pci_up(wlc_hw->sih); ++ ++ /* reset the d11 core */ ++ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); ++ ++ return 0; ++} ++ ++static int brcms_b_up_finish(struct brcms_hardware *wlc_hw) ++{ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ wlc_hw->up = true; ++ wlc_phy_hw_state_upd(wlc_hw->band->pi, true); ++ ++ /* FULLY enable dynamic power control and d11 core interrupt */ ++ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); ++ brcms_intrson(wlc_hw->wlc->wl); ++ return 0; ++} ++ ++/* ++ * Write WME tunable parameters for retransmit/max rate ++ * from wlc struct to ucode ++ */ ++static void brcms_c_wme_retries_write(struct brcms_c_info *wlc) ++{ ++ int ac; ++ ++ /* Need clock to do this */ ++ if (!wlc->clk) ++ return; ++ ++ for (ac = 0; ac < AC_COUNT; ac++) ++ brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac), ++ wlc->wme_retries[ac]); ++} ++ ++/* make interface operational */ ++int brcms_c_up(struct brcms_c_info *wlc) ++{ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ /* HW is turned off so don't try to access it */ ++ if (wlc->pub->hw_off || brcms_deviceremoved(wlc)) ++ return -ENOMEDIUM; ++ ++ if (!wlc->pub->hw_up) { ++ brcms_b_hw_up(wlc->hw); ++ wlc->pub->hw_up = true; ++ } ++ ++ if ((wlc->pub->boardflags & BFL_FEM) ++ && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) { ++ if (wlc->pub->boardrev >= 0x1250 ++ && (wlc->pub->boardflags & BFL_FEM_BT)) ++ brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, ++ MHF5_4313_GPIOCTRL, BRCM_BAND_ALL); ++ else ++ brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE, ++ MHF4_EXTPA_ENABLE, BRCM_BAND_ALL); ++ } ++ ++ /* ++ * Need to read the hwradio status here to cover the case where the ++ * system is loaded with the hw radio disabled. We do not want to bring ++ * the driver up in this case. If radio is disabled, abort up, lower ++ * power, start radio timer and return 0(for NDIS) don't call ++ * radio_update to avoid looping brcms_c_up. ++ * ++ * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only ++ */ ++ if (!wlc->pub->radio_disabled) { ++ int status = brcms_b_up_prep(wlc->hw); ++ if (status == -ENOMEDIUM) { ++ if (!mboolisset ++ (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) { ++ struct brcms_bss_cfg *bsscfg = wlc->bsscfg; ++ mboolset(wlc->pub->radio_disabled, ++ WL_RADIO_HW_DISABLE); ++ ++ if (bsscfg->enable && bsscfg->BSS) ++ wiphy_err(wlc->wiphy, "wl%d: up" ++ ": rfdisable -> " ++ "bsscfg_disable()\n", ++ wlc->pub->unit); ++ } ++ } ++ } ++ ++ if (wlc->pub->radio_disabled) { ++ brcms_c_radio_monitor_start(wlc); ++ return 0; ++ } ++ ++ /* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */ ++ wlc->clk = true; ++ ++ brcms_c_radio_monitor_stop(wlc); ++ ++ /* Set EDCF hostflags */ ++ brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL); ++ ++ brcms_init(wlc->wl); ++ wlc->pub->up = true; ++ ++ if (wlc->bandinit_pending) { ++ brcms_c_suspend_mac_and_wait(wlc); ++ brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec); ++ wlc->bandinit_pending = false; ++ brcms_c_enable_mac(wlc); ++ } ++ ++ brcms_b_up_finish(wlc->hw); ++ ++ /* Program the TX wme params with the current settings */ ++ brcms_c_wme_retries_write(wlc); ++ ++ /* start one second watchdog timer */ ++ brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true); ++ wlc->WDarmed = true; ++ ++ /* ensure antenna config is up to date */ ++ brcms_c_stf_phy_txant_upd(wlc); ++ /* ensure LDPC config is in sync */ ++ brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc); ++ ++ return 0; ++} ++ ++static uint brcms_c_down_del_timer(struct brcms_c_info *wlc) ++{ ++ uint callbacks = 0; ++ ++ return callbacks; ++} ++ ++static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw) ++{ ++ bool dev_gone; ++ uint callbacks = 0; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ if (!wlc_hw->up) ++ return callbacks; ++ ++ dev_gone = brcms_deviceremoved(wlc_hw->wlc); ++ ++ /* disable interrupts */ ++ if (dev_gone) ++ wlc_hw->wlc->macintmask = 0; ++ else { ++ /* now disable interrupts */ ++ brcms_intrsoff(wlc_hw->wlc->wl); ++ ++ /* ensure we're running on the pll clock again */ ++ brcms_b_clkctl_clk(wlc_hw, CLK_FAST); ++ } ++ /* down phy at the last of this stage */ ++ callbacks += wlc_phy_down(wlc_hw->band->pi); ++ ++ return callbacks; ++} ++ ++static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) ++{ ++ uint callbacks = 0; ++ bool dev_gone; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ ++ if (!wlc_hw->up) ++ return callbacks; ++ ++ wlc_hw->up = false; ++ wlc_phy_hw_state_upd(wlc_hw->band->pi, false); ++ ++ dev_gone = brcms_deviceremoved(wlc_hw->wlc); ++ ++ if (dev_gone) { ++ wlc_hw->sbclk = false; ++ wlc_hw->clk = false; ++ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); ++ ++ /* reclaim any posted packets */ ++ brcms_c_flushqueues(wlc_hw->wlc); ++ } else { ++ ++ /* Reset and disable the core */ ++ if (ai_iscoreup(wlc_hw->sih)) { ++ if (R_REG(&wlc_hw->regs->maccontrol) & ++ MCTL_EN_MAC) ++ brcms_c_suspend_mac_and_wait(wlc_hw->wlc); ++ callbacks += brcms_reset(wlc_hw->wlc->wl); ++ brcms_c_coredisable(wlc_hw); ++ } ++ ++ /* turn off primary xtal and pll */ ++ if (!wlc_hw->noreset) { ++ ai_pci_down(wlc_hw->sih); ++ brcms_b_xtal(wlc_hw, OFF); ++ } ++ } ++ ++ return callbacks; ++} ++ ++/* ++ * Mark the interface nonoperational, stop the software mechanisms, ++ * disable the hardware, free any transient buffer state. ++ * Return a count of the number of driver callbacks still pending. ++ */ ++uint brcms_c_down(struct brcms_c_info *wlc) ++{ ++ ++ uint callbacks = 0; ++ int i; ++ bool dev_gone = false; ++ struct brcms_txq_info *qi; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ /* check if we are already in the going down path */ ++ if (wlc->going_down) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return" ++ "\n", wlc->pub->unit, __func__); ++ return 0; ++ } ++ if (!wlc->pub->up) ++ return callbacks; ++ ++ /* in between, mpc could try to bring down again.. */ ++ wlc->going_down = true; ++ ++ callbacks += brcms_b_bmac_down_prep(wlc->hw); ++ ++ dev_gone = brcms_deviceremoved(wlc); ++ ++ /* Call any registered down handlers */ ++ for (i = 0; i < BRCMS_MAXMODULES; i++) { ++ if (wlc->modulecb[i].down_fn) ++ callbacks += ++ wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl); ++ } ++ ++ /* cancel the watchdog timer */ ++ if (wlc->WDarmed) { ++ if (!brcms_del_timer(wlc->wdtimer)) ++ callbacks++; ++ wlc->WDarmed = false; ++ } ++ /* cancel all other timers */ ++ callbacks += brcms_c_down_del_timer(wlc); ++ ++ wlc->pub->up = false; ++ ++ wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL); ++ ++ /* clear txq flow control */ ++ brcms_c_txflowcontrol_reset(wlc); ++ ++ /* flush tx queues */ ++ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) ++ brcmu_pktq_flush(&qi->q, true, NULL, NULL); ++ ++ callbacks += brcms_b_down_finish(wlc->hw); ++ ++ /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */ ++ wlc->clk = false; ++ ++ wlc->going_down = false; ++ return callbacks; ++} ++ ++/* Set the current gmode configuration */ ++int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) ++{ ++ int ret = 0; ++ uint i; ++ struct brcms_c_rateset rs; ++ /* Default to 54g Auto */ ++ /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */ ++ s8 shortslot = BRCMS_SHORTSLOT_AUTO; ++ bool shortslot_restrict = false; /* Restrict association to stations ++ * that support shortslot ++ */ ++ bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */ ++ /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */ ++ int preamble = BRCMS_PLCP_LONG; ++ bool preamble_restrict = false; /* Restrict association to stations ++ * that support short preambles ++ */ ++ struct brcms_band *band; ++ ++ /* if N-support is enabled, allow Gmode set as long as requested ++ * Gmode is not GMODE_LEGACY_B ++ */ ++ if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B) ++ return -ENOTSUPP; ++ ++ /* verify that we are dealing with 2G band and grab the band pointer */ ++ if (wlc->band->bandtype == BRCM_BAND_2G) ++ band = wlc->band; ++ else if ((wlc->pub->_nbands > 1) && ++ (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G)) ++ band = wlc->bandstate[OTHERBANDUNIT(wlc)]; ++ else ++ return -EINVAL; ++ ++ /* Legacy or bust when no OFDM is supported by regulatory */ ++ if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) & ++ BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B)) ++ return -EINVAL; ++ ++ /* update configuration value */ ++ if (config == true) ++ brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); ++ ++ /* Clear rateset override */ ++ memset(&rs, 0, sizeof(struct brcms_c_rateset)); ++ ++ switch (gmode) { ++ case GMODE_LEGACY_B: ++ shortslot = BRCMS_SHORTSLOT_OFF; ++ brcms_c_rateset_copy(&gphy_legacy_rates, &rs); ++ ++ break; ++ ++ case GMODE_LRS: ++ break; ++ ++ case GMODE_AUTO: ++ /* Accept defaults */ ++ break; ++ ++ case GMODE_ONLY: ++ ofdm_basic = true; ++ preamble = BRCMS_PLCP_SHORT; ++ preamble_restrict = true; ++ break; ++ ++ case GMODE_PERFORMANCE: ++ shortslot = BRCMS_SHORTSLOT_ON; ++ shortslot_restrict = true; ++ ofdm_basic = true; ++ preamble = BRCMS_PLCP_SHORT; ++ preamble_restrict = true; ++ break; ++ ++ default: ++ /* Error */ ++ wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n", ++ wlc->pub->unit, __func__, gmode); ++ return -ENOTSUPP; ++ } ++ ++ band->gmode = gmode; ++ ++ wlc->shortslot_override = shortslot; ++ ++ /* Use the default 11g rateset */ ++ if (!rs.count) ++ brcms_c_rateset_copy(&cck_ofdm_rates, &rs); ++ ++ if (ofdm_basic) { ++ for (i = 0; i < rs.count; i++) { ++ if (rs.rates[i] == BRCM_RATE_6M ++ || rs.rates[i] == BRCM_RATE_12M ++ || rs.rates[i] == BRCM_RATE_24M) ++ rs.rates[i] |= BRCMS_RATE_FLAG; ++ } ++ } ++ ++ /* Set default bss rateset */ ++ wlc->default_bss->rateset.count = rs.count; ++ memcpy(wlc->default_bss->rateset.rates, rs.rates, ++ sizeof(wlc->default_bss->rateset.rates)); ++ ++ return ret; ++} ++ ++int brcms_c_set_nmode(struct brcms_c_info *wlc) ++{ ++ uint i; ++ s32 nmode = AUTO; ++ ++ if (wlc->stf->txstreams == WL_11N_3x3) ++ nmode = WL_11N_3x3; ++ else ++ nmode = WL_11N_2x2; ++ ++ /* force GMODE_AUTO if NMODE is ON */ ++ brcms_c_set_gmode(wlc, GMODE_AUTO, true); ++ if (nmode == WL_11N_3x3) ++ wlc->pub->_n_enab = SUPPORT_HT; ++ else ++ wlc->pub->_n_enab = SUPPORT_11N; ++ wlc->default_bss->flags |= BRCMS_BSS_HT; ++ /* add the mcs rates to the default and hw ratesets */ ++ brcms_c_rateset_mcs_build(&wlc->default_bss->rateset, ++ wlc->stf->txstreams); ++ for (i = 0; i < wlc->pub->_nbands; i++) ++ memcpy(wlc->bandstate[i]->hw_rateset.mcs, ++ wlc->default_bss->rateset.mcs, MCSSET_LEN); ++ ++ return 0; ++} ++ ++static int ++brcms_c_set_internal_rateset(struct brcms_c_info *wlc, ++ struct brcms_c_rateset *rs_arg) ++{ ++ struct brcms_c_rateset rs, new; ++ uint bandunit; ++ ++ memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset)); ++ ++ /* check for bad count value */ ++ if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES)) ++ return -EINVAL; ++ ++ /* try the current band */ ++ bandunit = wlc->band->bandunit; ++ memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); ++ if (brcms_c_rate_hwrs_filter_sort_validate ++ (&new, &wlc->bandstate[bandunit]->hw_rateset, true, ++ wlc->stf->txstreams)) ++ goto good; ++ ++ /* try the other band */ ++ if (brcms_is_mband_unlocked(wlc)) { ++ bandunit = OTHERBANDUNIT(wlc); ++ memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); ++ if (brcms_c_rate_hwrs_filter_sort_validate(&new, ++ &wlc-> ++ bandstate[bandunit]-> ++ hw_rateset, true, ++ wlc->stf->txstreams)) ++ goto good; ++ } ++ ++ return -EBADE; ++ ++ good: ++ /* apply new rateset */ ++ memcpy(&wlc->default_bss->rateset, &new, ++ sizeof(struct brcms_c_rateset)); ++ memcpy(&wlc->bandstate[bandunit]->defrateset, &new, ++ sizeof(struct brcms_c_rateset)); ++ return 0; ++} ++ ++static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc) ++{ ++ u8 r; ++ bool war = false; ++ ++ if (wlc->bsscfg->associated) ++ r = wlc->bsscfg->current_bss->rateset.rates[0]; ++ else ++ r = wlc->default_bss->rateset.rates[0]; ++ ++ wlc_phy_ofdm_rateset_war(wlc->band->pi, war); ++} ++ ++int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel) ++{ ++ u16 chspec = ch20mhz_chspec(channel); ++ ++ if (channel < 0 || channel > MAXCHANNEL) ++ return -EINVAL; ++ ++ if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec)) ++ return -EINVAL; ++ ++ ++ if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) { ++ if (wlc->band->bandunit != chspec_bandunit(chspec)) ++ wlc->bandinit_pending = true; ++ else ++ wlc->bandinit_pending = false; ++ } ++ ++ wlc->default_bss->chanspec = chspec; ++ /* brcms_c_BSSinit() will sanitize the rateset before ++ * using it.. */ ++ if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) { ++ brcms_c_set_home_chanspec(wlc, chspec); ++ brcms_c_suspend_mac_and_wait(wlc); ++ brcms_c_set_chanspec(wlc, chspec); ++ brcms_c_enable_mac(wlc); ++ } ++ return 0; ++} ++ ++int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl) ++{ ++ int ac; ++ ++ if (srl < 1 || srl > RETRY_SHORT_MAX || ++ lrl < 1 || lrl > RETRY_SHORT_MAX) ++ return -EINVAL; ++ ++ wlc->SRL = srl; ++ wlc->LRL = lrl; ++ ++ brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL); ++ ++ for (ac = 0; ac < AC_COUNT; ac++) { ++ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], ++ EDCF_SHORT, wlc->SRL); ++ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], ++ EDCF_LONG, wlc->LRL); ++ } ++ brcms_c_wme_retries_write(wlc); ++ ++ return 0; ++} ++ ++void brcms_c_get_current_rateset(struct brcms_c_info *wlc, ++ struct brcm_rateset *currs) ++{ ++ struct brcms_c_rateset *rs; ++ ++ if (wlc->pub->associated) ++ rs = &wlc->bsscfg->current_bss->rateset; ++ else ++ rs = &wlc->default_bss->rateset; ++ ++ /* Copy only legacy rateset section */ ++ currs->count = rs->count; ++ memcpy(&currs->rates, &rs->rates, rs->count); ++} ++ ++int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) ++{ ++ struct brcms_c_rateset internal_rs; ++ int bcmerror; ++ ++ if (rs->count > BRCMS_NUMRATES) ++ return -ENOBUFS; ++ ++ memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); ++ ++ /* Copy only legacy rateset section */ ++ internal_rs.count = rs->count; ++ memcpy(&internal_rs.rates, &rs->rates, internal_rs.count); ++ ++ /* merge rateset coming in with the current mcsset */ ++ if (wlc->pub->_n_enab & SUPPORT_11N) { ++ struct brcms_bss_info *mcsset_bss; ++ if (wlc->bsscfg->associated) ++ mcsset_bss = wlc->bsscfg->current_bss; ++ else ++ mcsset_bss = wlc->default_bss; ++ memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0], ++ MCSSET_LEN); ++ } ++ ++ bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs); ++ if (!bcmerror) ++ brcms_c_ofdm_rateset_war(wlc); ++ ++ return bcmerror; ++} ++ ++int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) ++{ ++ if (period < DOT11_MIN_BEACON_PERIOD || ++ period > DOT11_MAX_BEACON_PERIOD) ++ return -EINVAL; ++ ++ wlc->default_bss->beacon_period = period; ++ return 0; ++} ++ ++u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx) ++{ ++ return wlc->band->phytype; ++} ++ ++void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override) ++{ ++ wlc->shortslot_override = sslot_override; ++ ++ /* ++ * shortslot is an 11g feature, so no more work if we are ++ * currently on the 5G band ++ */ ++ if (wlc->band->bandtype == BRCM_BAND_5G) ++ return; ++ ++ if (wlc->pub->up && wlc->pub->associated) { ++ /* let watchdog or beacon processing update shortslot */ ++ } else if (wlc->pub->up) { ++ /* unassociated shortslot is off */ ++ brcms_c_switch_shortslot(wlc, false); ++ } else { ++ /* driver is down, so just update the brcms_c_info ++ * value */ ++ if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO) ++ wlc->shortslot = false; ++ else ++ wlc->shortslot = ++ (wlc->shortslot_override == ++ BRCMS_SHORTSLOT_ON); ++ } ++} ++ ++/* ++ * register watchdog and down handlers. ++ */ ++int brcms_c_module_register(struct brcms_pub *pub, ++ const char *name, struct brcms_info *hdl, ++ int (*d_fn)(void *handle)) ++{ ++ struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; ++ int i; ++ ++ /* find an empty entry and just add, no duplication check! */ ++ for (i = 0; i < BRCMS_MAXMODULES; i++) { ++ if (wlc->modulecb[i].name[0] == '\0') { ++ strncpy(wlc->modulecb[i].name, name, ++ sizeof(wlc->modulecb[i].name) - 1); ++ wlc->modulecb[i].hdl = hdl; ++ wlc->modulecb[i].down_fn = d_fn; ++ return 0; ++ } ++ } ++ ++ return -ENOSR; ++} ++ ++/* unregister module callbacks */ ++int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, ++ struct brcms_info *hdl) ++{ ++ struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; ++ int i; ++ ++ if (wlc == NULL) ++ return -ENODATA; ++ ++ for (i = 0; i < BRCMS_MAXMODULES; i++) { ++ if (!strcmp(wlc->modulecb[i].name, name) && ++ (wlc->modulecb[i].hdl == hdl)) { ++ memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); ++ return 0; ++ } ++ } ++ ++ /* table not found! */ ++ return -ENODATA; ++} ++ ++#ifdef BCMDBG ++static const char * const supr_reason[] = { ++ "None", "PMQ Entry", "Flush request", ++ "Previous frag failure", "Channel mismatch", ++ "Lifetime Expiry", "Underflow" ++}; ++ ++static void brcms_c_print_txs_status(u16 s) ++{ ++ printk(KERN_DEBUG "[15:12] %d frame attempts\n", ++ (s & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT); ++ printk(KERN_DEBUG " [11:8] %d rts attempts\n", ++ (s & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT); ++ printk(KERN_DEBUG " [7] %d PM mode indicated\n", ++ ((s & TX_STATUS_PMINDCTD) ? 1 : 0)); ++ printk(KERN_DEBUG " [6] %d intermediate status\n", ++ ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0)); ++ printk(KERN_DEBUG " [5] %d AMPDU\n", ++ (s & TX_STATUS_AMPDU) ? 1 : 0); ++ printk(KERN_DEBUG " [4:2] %d Frame Suppressed Reason (%s)\n", ++ ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT), ++ supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]); ++ printk(KERN_DEBUG " [1] %d acked\n", ++ ((s & TX_STATUS_ACK_RCV) ? 1 : 0)); ++} ++#endif /* BCMDBG */ ++ ++void brcms_c_print_txstatus(struct tx_status *txs) ++{ ++#if defined(BCMDBG) ++ u16 s = txs->status; ++ u16 ackphyrxsh = txs->ackphyrxsh; ++ ++ printk(KERN_DEBUG "\ntxpkt (MPDU) Complete\n"); ++ ++ printk(KERN_DEBUG "FrameID: %04x ", txs->frameid); ++ printk(KERN_DEBUG "TxStatus: %04x", s); ++ printk(KERN_DEBUG "\n"); ++ ++ brcms_c_print_txs_status(s); ++ ++ printk(KERN_DEBUG "LastTxTime: %04x ", txs->lasttxtime); ++ printk(KERN_DEBUG "Seq: %04x ", txs->sequence); ++ printk(KERN_DEBUG "PHYTxStatus: %04x ", txs->phyerr); ++ printk(KERN_DEBUG "RxAckRSSI: %04x ", ++ (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT); ++ printk(KERN_DEBUG "RxAckSQ: %04x", ++ (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); ++ printk(KERN_DEBUG "\n"); ++#endif /* defined(BCMDBG) */ ++} ++ ++bool brcms_c_chipmatch(u16 vendor, u16 device) ++{ ++ if (vendor != PCI_VENDOR_ID_BROADCOM) { ++ pr_err("chipmatch: unknown vendor id %04x\n", vendor); ++ return false; ++ } ++ ++ if (device == BCM43224_D11N_ID_VEN1) ++ return true; ++ if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID)) ++ return true; ++ if (device == BCM4313_D11N2G_ID) ++ return true; ++ if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID)) ++ return true; ++ ++ pr_err("chipmatch: unknown device id %04x\n", device); ++ return false; ++} ++ ++#if defined(BCMDBG) ++void brcms_c_print_txdesc(struct d11txh *txh) ++{ ++ u16 mtcl = le16_to_cpu(txh->MacTxControlLow); ++ u16 mtch = le16_to_cpu(txh->MacTxControlHigh); ++ u16 mfc = le16_to_cpu(txh->MacFrameControl); ++ u16 tfest = le16_to_cpu(txh->TxFesTimeNormal); ++ u16 ptcw = le16_to_cpu(txh->PhyTxControlWord); ++ u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1); ++ u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr); ++ u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts); ++ u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts); ++ u16 mainrates = le16_to_cpu(txh->MainRates); ++ u16 xtraft = le16_to_cpu(txh->XtraFrameTypes); ++ u8 *iv = txh->IV; ++ u8 *ra = txh->TxFrameRA; ++ u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback); ++ u8 *rtspfb = txh->RTSPLCPFallback; ++ u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback); ++ u8 *fragpfb = txh->FragPLCPFallback; ++ u16 fragdfb = le16_to_cpu(txh->FragDurFallback); ++ u16 mmodelen = le16_to_cpu(txh->MModeLen); ++ u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen); ++ u16 tfid = le16_to_cpu(txh->TxFrameID); ++ u16 txs = le16_to_cpu(txh->TxStatus); ++ u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus); ++ u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT); ++ u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR); ++ u16 mmbyte = le16_to_cpu(txh->MinMBytes); ++ ++ u8 *rtsph = txh->RTSPhyHeader; ++ struct ieee80211_rts rts = txh->rts_frame; ++ char hexbuf[256]; ++ ++ /* add plcp header along with txh descriptor */ ++ printk(KERN_DEBUG "Raw TxDesc + plcp header:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ++ txh, sizeof(struct d11txh) + 48); ++ ++ printk(KERN_DEBUG "TxCtlLow: %04x ", mtcl); ++ printk(KERN_DEBUG "TxCtlHigh: %04x ", mtch); ++ printk(KERN_DEBUG "FC: %04x ", mfc); ++ printk(KERN_DEBUG "FES Time: %04x\n", tfest); ++ printk(KERN_DEBUG "PhyCtl: %04x%s ", ptcw, ++ (ptcw & PHY_TXC_SHORT_HDR) ? " short" : ""); ++ printk(KERN_DEBUG "PhyCtl_1: %04x ", ptcw_1); ++ printk(KERN_DEBUG "PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); ++ printk(KERN_DEBUG "PhyCtl_1_Rts: %04x ", ptcw_1_Rts); ++ printk(KERN_DEBUG "PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); ++ printk(KERN_DEBUG "MainRates: %04x ", mainrates); ++ printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft); ++ printk(KERN_DEBUG "\n"); ++ ++ brcmu_format_hex(hexbuf, iv, sizeof(txh->IV)); ++ printk(KERN_DEBUG "SecIV: %s\n", hexbuf); ++ brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA)); ++ printk(KERN_DEBUG "RA: %s\n", hexbuf); ++ ++ printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb); ++ brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback)); ++ printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); ++ printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb); ++ brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback)); ++ printk(KERN_DEBUG "PLCP: %s ", hexbuf); ++ printk(KERN_DEBUG "DUR: %04x", fragdfb); ++ printk(KERN_DEBUG "\n"); ++ ++ printk(KERN_DEBUG "MModeLen: %04x ", mmodelen); ++ printk(KERN_DEBUG "MModeFbrLen: %04x\n", mmodefbrlen); ++ ++ printk(KERN_DEBUG "FrameID: %04x\n", tfid); ++ printk(KERN_DEBUG "TxStatus: %04x\n", txs); ++ ++ printk(KERN_DEBUG "MaxNumMpdu: %04x\n", mnmpdu); ++ printk(KERN_DEBUG "MaxAggbyte: %04x\n", mabyte); ++ printk(KERN_DEBUG "MaxAggbyte_fb: %04x\n", mabyte_f); ++ printk(KERN_DEBUG "MinByte: %04x\n", mmbyte); ++ ++ brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader)); ++ printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); ++ brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame)); ++ printk(KERN_DEBUG "RTS Frame: %s", hexbuf); ++ printk(KERN_DEBUG "\n"); ++} ++#endif /* defined(BCMDBG) */ ++ ++#if defined(BCMDBG) ++int ++brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf, ++ int len) ++{ ++ int i; ++ char *p = buf; ++ char hexstr[16]; ++ int slen = 0, nlen = 0; ++ u32 bit; ++ const char *name; ++ ++ if (len < 2 || !buf) ++ return 0; ++ ++ buf[0] = '\0'; ++ ++ for (i = 0; flags != 0; i++) { ++ bit = bd[i].bit; ++ name = bd[i].name; ++ if (bit == 0 && flags != 0) { ++ /* print any unnamed bits */ ++ snprintf(hexstr, 16, "0x%X", flags); ++ name = hexstr; ++ flags = 0; /* exit loop */ ++ } else if ((flags & bit) == 0) ++ continue; ++ flags &= ~bit; ++ nlen = strlen(name); ++ slen += nlen; ++ /* count btwn flag space */ ++ if (flags != 0) ++ slen += 1; ++ /* need NULL char as well */ ++ if (len <= slen) ++ break; ++ /* copy NULL char but don't count it */ ++ strncpy(p, name, nlen + 1); ++ p += nlen; ++ /* copy btwn flag space and NULL char */ ++ if (flags != 0) ++ p += snprintf(p, 2, " "); ++ len -= slen; ++ } ++ ++ /* indicate the str was too short */ ++ if (flags != 0) { ++ if (len < 2) ++ p -= 2 - len; /* overwrite last char */ ++ p += snprintf(p, 2, ">"); ++ } ++ ++ return (int)(p - buf); ++} ++#endif /* defined(BCMDBG) */ ++ ++#if defined(BCMDBG) ++void brcms_c_print_rxh(struct d11rxhdr *rxh) ++{ ++ u16 len = rxh->RxFrameSize; ++ u16 phystatus_0 = rxh->PhyRxStatus_0; ++ u16 phystatus_1 = rxh->PhyRxStatus_1; ++ u16 phystatus_2 = rxh->PhyRxStatus_2; ++ u16 phystatus_3 = rxh->PhyRxStatus_3; ++ u16 macstatus1 = rxh->RxStatus1; ++ u16 macstatus2 = rxh->RxStatus2; ++ char flagstr[64]; ++ char lenbuf[20]; ++ static const struct brcms_c_bit_desc macstat_flags[] = { ++ {RXS_FCSERR, "FCSErr"}, ++ {RXS_RESPFRAMETX, "Reply"}, ++ {RXS_PBPRES, "PADDING"}, ++ {RXS_DECATMPT, "DeCr"}, ++ {RXS_DECERR, "DeCrErr"}, ++ {RXS_BCNSENT, "Bcn"}, ++ {0, NULL} ++ }; ++ ++ printk(KERN_DEBUG "Raw RxDesc:\n"); ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh, ++ sizeof(struct d11rxhdr)); ++ ++ brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64); ++ ++ snprintf(lenbuf, sizeof(lenbuf), "0x%x", len); ++ ++ printk(KERN_DEBUG "RxFrameSize: %6s (%d)%s\n", lenbuf, len, ++ (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : ""); ++ printk(KERN_DEBUG "RxPHYStatus: %04x %04x %04x %04x\n", ++ phystatus_0, phystatus_1, phystatus_2, phystatus_3); ++ printk(KERN_DEBUG "RxMACStatus: %x %s\n", macstatus1, flagstr); ++ printk(KERN_DEBUG "RXMACaggtype: %x\n", ++ (macstatus2 & RXS_AGGTYPE_MASK)); ++ printk(KERN_DEBUG "RxTSFTime: %04x\n", rxh->RxTSFTime); ++} ++#endif /* defined(BCMDBG) */ ++ ++u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) ++{ ++ u16 table_ptr; ++ u8 phy_rate, index; ++ ++ /* get the phy specific rate encoding for the PLCP SIGNAL field */ ++ if (is_ofdm_rate(rate)) ++ table_ptr = M_RT_DIRMAP_A; ++ else ++ table_ptr = M_RT_DIRMAP_B; ++ ++ /* for a given rate, the LS-nibble of the PLCP SIGNAL field is ++ * the index into the rate table. ++ */ ++ phy_rate = rate_info[rate] & BRCMS_RATE_MASK; ++ index = phy_rate & 0xf; ++ ++ /* Find the SHM pointer to the rate table entry by looking in the ++ * Direct-map Table ++ */ ++ return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2)); ++} ++ ++static bool ++brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q, ++ struct sk_buff *pkt, int prec, bool head) ++{ ++ struct sk_buff *p; ++ int eprec = -1; /* precedence to evict from */ ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(q, prec)) ++ eprec = prec; ++ else if (pktq_full(q)) { ++ p = brcmu_pktq_peek_tail(q, &eprec); ++ if (eprec > prec) { ++ wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d" ++ "\n", __func__, eprec, prec); ++ return false; ++ } ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ bool discard_oldest; ++ ++ discard_oldest = ac_bitmap_tst(0, eprec); ++ ++ /* Refuse newer packet unless configured to discard oldest */ ++ if (eprec == prec && !discard_oldest) { ++ wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d" ++ "\n", __func__, prec); ++ return false; ++ } ++ ++ /* Evict packet according to discard policy */ ++ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : ++ brcmu_pktq_pdeq_tail(q, eprec); ++ brcmu_pkt_buf_free_skb(p); ++ } ++ ++ /* Enqueue */ ++ if (head) ++ p = brcmu_pktq_penq_head(q, prec, pkt); ++ else ++ p = brcmu_pktq_penq(q, prec, pkt); ++ ++ return true; ++} ++ ++/* ++ * Attempts to queue a packet onto a multiple-precedence queue, ++ * if necessary evicting a lower precedence packet from the queue. ++ * ++ * 'prec' is the precedence number that has already been mapped ++ * from the packet priority. ++ * ++ * Returns true if packet consumed (queued), false if not. ++ */ ++static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q, ++ struct sk_buff *pkt, int prec) ++{ ++ return brcms_c_prec_enq_head(wlc, q, pkt, prec, false); ++} ++ ++void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, ++ struct sk_buff *sdu, uint prec) ++{ ++ struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */ ++ struct pktq *q = &qi->q; ++ int prio; ++ ++ prio = sdu->priority; ++ ++ if (!brcms_c_prec_enq(wlc, q, sdu, prec)) { ++ /* ++ * we might hit this condtion in case ++ * packet flooding from mac80211 stack ++ */ ++ brcmu_pkt_buf_free_skb(sdu); ++ } ++} ++ ++/* ++ * bcmc_fid_generate: ++ * Generate frame ID for a BCMC packet. The frag field is not used ++ * for MC frames so is used as part of the sequence number. ++ */ ++static inline u16 ++bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg, ++ struct d11txh *txh) ++{ ++ u16 frameid; ++ ++ frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK | ++ TXFID_QUEUE_MASK); ++ frameid |= ++ (((wlc-> ++ mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | ++ TX_BCMC_FIFO; ++ ++ return frameid; ++} ++ ++static uint ++brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec, ++ u8 preamble_type) ++{ ++ uint dur = 0; ++ ++ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n", ++ wlc->pub->unit, rspec, preamble_type); ++ /* ++ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that ++ * is less than or equal to the rate of the immediately previous ++ * frame in the FES ++ */ ++ rspec = brcms_basic_rate(wlc, rspec); ++ /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */ ++ dur = ++ brcms_c_calc_frame_time(wlc, rspec, preamble_type, ++ (DOT11_ACK_LEN + FCS_LEN)); ++ return dur; ++} ++ ++static uint ++brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec, ++ u8 preamble_type) ++{ ++ BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n", ++ wlc->pub->unit, rspec, preamble_type); ++ return brcms_c_calc_ack_time(wlc, rspec, preamble_type); ++} ++ ++static uint ++brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec, ++ u8 preamble_type) ++{ ++ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, " ++ "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type); ++ /* ++ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that ++ * is less than or equal to the rate of the immediately previous ++ * frame in the FES ++ */ ++ rspec = brcms_basic_rate(wlc, rspec); ++ /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */ ++ return brcms_c_calc_frame_time(wlc, rspec, preamble_type, ++ (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN + ++ FCS_LEN)); ++} ++ ++/* brcms_c_compute_frame_dur() ++ * ++ * Calculate the 802.11 MAC header DUR field for MPDU ++ * DUR for a single frame = 1 SIFS + 1 ACK ++ * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time ++ * ++ * rate MPDU rate in unit of 500kbps ++ * next_frag_len next MPDU length in bytes ++ * preamble_type use short/GF or long/MM PLCP header ++ */ ++static u16 ++brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate, ++ u8 preamble_type, uint next_frag_len) ++{ ++ u16 dur, sifs; ++ ++ sifs = get_sifs(wlc->band); ++ ++ dur = sifs; ++ dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type); ++ ++ if (next_frag_len) { ++ /* Double the current DUR to get 2 SIFS + 2 ACKs */ ++ dur *= 2; ++ /* add another SIFS and the frag time */ ++ dur += sifs; ++ dur += ++ (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type, ++ next_frag_len); ++ } ++ return dur; ++} ++ ++/* The opposite of brcms_c_calc_frame_time */ ++static uint ++brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec, ++ u8 preamble_type, uint dur) ++{ ++ uint nsyms, mac_len, Ndps, kNdps; ++ uint rate = rspec2rate(ratespec); ++ ++ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n", ++ wlc->pub->unit, ratespec, preamble_type, dur); ++ ++ if (is_mcs_rate(ratespec)) { ++ uint mcs = ratespec & RSPEC_RATE_MASK; ++ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); ++ dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); ++ /* payload calculation matches that of regular ofdm */ ++ if (wlc->band->bandtype == BRCM_BAND_2G) ++ dur -= DOT11_OFDM_SIGNAL_EXTENSION; ++ /* kNdbps = kbps * 4 */ ++ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), ++ rspec_issgi(ratespec)) * 4; ++ nsyms = dur / APHY_SYMBOL_TIME; ++ mac_len = ++ ((nsyms * kNdps) - ++ ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000; ++ } else if (is_ofdm_rate(ratespec)) { ++ dur -= APHY_PREAMBLE_TIME; ++ dur -= APHY_SIGNAL_TIME; ++ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ ++ Ndps = rate * 2; ++ nsyms = dur / APHY_SYMBOL_TIME; ++ mac_len = ++ ((nsyms * Ndps) - ++ (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8; ++ } else { ++ if (preamble_type & BRCMS_SHORT_PREAMBLE) ++ dur -= BPHY_PLCP_SHORT_TIME; ++ else ++ dur -= BPHY_PLCP_TIME; ++ mac_len = dur * rate; ++ /* divide out factor of 2 in rate (1/2 mbps) */ ++ mac_len = mac_len / 8 / 2; ++ } ++ return mac_len; ++} ++ ++/* ++ * Return true if the specified rate is supported by the specified band. ++ * BRCM_BAND_AUTO indicates the current band. ++ */ ++static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band, ++ bool verbose) ++{ ++ struct brcms_c_rateset *hw_rateset; ++ uint i; ++ ++ if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype)) ++ hw_rateset = &wlc->band->hw_rateset; ++ else if (wlc->pub->_nbands > 1) ++ hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset; ++ else ++ /* other band specified and we are a single band device */ ++ return false; ++ ++ /* check if this is a mimo rate */ ++ if (is_mcs_rate(rspec)) { ++ if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE) ++ goto error; ++ ++ return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK)); ++ } ++ ++ for (i = 0; i < hw_rateset->count; i++) ++ if (hw_rateset->rates[i] == rspec2rate(rspec)) ++ return true; ++ error: ++ if (verbose) ++ wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x " ++ "not in hw_rateset\n", wlc->pub->unit, rspec); ++ ++ return false; ++} ++ ++static u32 ++mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, ++ u32 int_val) ++{ ++ u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; ++ u8 rate = int_val & NRATE_RATE_MASK; ++ u32 rspec; ++ bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE); ++ bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT); ++ bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY) ++ == NRATE_OVERRIDE_MCS_ONLY); ++ int bcmerror = 0; ++ ++ if (!ismcs) ++ return (u32) rate; ++ ++ /* validate the combination of rate/mcs/stf is allowed */ ++ if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) { ++ /* mcs only allowed when nmode */ ++ if (stf > PHY_TXC1_MODE_SDM) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n", ++ wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ ++ /* mcs 32 is a special case, DUP mode 40 only */ ++ if (rate == 32) { ++ if (!CHSPEC_IS40(wlc->home_chanspec) || ++ ((stf != PHY_TXC1_MODE_SISO) ++ && (stf != PHY_TXC1_MODE_CDD))) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs " ++ "32\n", wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ /* mcs > 7 must use stf SDM */ ++ } else if (rate > HIGHEST_SINGLE_STREAM_MCS) { ++ /* mcs > 7 must use stf SDM */ ++ if (stf != PHY_TXC1_MODE_SDM) { ++ BCMMSG(wlc->wiphy, "wl%d: enabling " ++ "SDM mode for mcs %d\n", ++ wlc->pub->unit, rate); ++ stf = PHY_TXC1_MODE_SDM; ++ } ++ } else { ++ /* ++ * MCS 0-7 may use SISO, CDD, and for ++ * phy_rev >= 3 STBC ++ */ ++ if ((stf > PHY_TXC1_MODE_STBC) || ++ (!BRCMS_STBC_CAP_PHY(wlc) ++ && (stf == PHY_TXC1_MODE_STBC))) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC" ++ "\n", wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ } ++ } else if (is_ofdm_rate(rate)) { ++ if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n", ++ wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ } else if (is_cck_rate(rate)) { ++ if ((cur_band->bandtype != BRCM_BAND_2G) ++ || (stf != PHY_TXC1_MODE_SISO)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n", ++ wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ } else { ++ wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n", ++ wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ /* make sure multiple antennae are available for non-siso rates */ ++ if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO " ++ "request\n", wlc->pub->unit, __func__); ++ bcmerror = -EINVAL; ++ goto done; ++ } ++ ++ rspec = rate; ++ if (ismcs) { ++ rspec |= RSPEC_MIMORATE; ++ /* For STBC populate the STC field of the ratespec */ ++ if (stf == PHY_TXC1_MODE_STBC) { ++ u8 stc; ++ stc = 1; /* Nss for single stream is always 1 */ ++ rspec |= (stc << RSPEC_STC_SHIFT); ++ } ++ } ++ ++ rspec |= (stf << RSPEC_STF_SHIFT); ++ ++ if (override_mcs_only) ++ rspec |= RSPEC_OVERRIDE_MCS_ONLY; ++ ++ if (issgi) ++ rspec |= RSPEC_SHORT_GI; ++ ++ if ((rate != 0) ++ && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true)) ++ return rate; ++ ++ return rspec; ++done: ++ return rate; ++} ++ ++/* ++ * Compute PLCP, but only requires actual rate and length of pkt. ++ * Rate is given in the driver standard multiple of 500 kbps. ++ * le is set for 11 Mbps rate if necessary. ++ * Broken out for PRQ. ++ */ ++ ++static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500, ++ uint length, u8 *plcp) ++{ ++ u16 usec = 0; ++ u8 le = 0; ++ ++ switch (rate_500) { ++ case BRCM_RATE_1M: ++ usec = length << 3; ++ break; ++ case BRCM_RATE_2M: ++ usec = length << 2; ++ break; ++ case BRCM_RATE_5M5: ++ usec = (length << 4) / 11; ++ if ((length << 4) - (usec * 11) > 0) ++ usec++; ++ break; ++ case BRCM_RATE_11M: ++ usec = (length << 3) / 11; ++ if ((length << 3) - (usec * 11) > 0) { ++ usec++; ++ if ((usec * 11) - (length << 3) >= 8) ++ le = D11B_PLCP_SIGNAL_LE; ++ } ++ break; ++ ++ default: ++ wiphy_err(wlc->wiphy, ++ "brcms_c_cck_plcp_set: unsupported rate %d\n", ++ rate_500); ++ rate_500 = BRCM_RATE_1M; ++ usec = length << 3; ++ break; ++ } ++ /* PLCP signal byte */ ++ plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */ ++ /* PLCP service byte */ ++ plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED); ++ /* PLCP length u16, little endian */ ++ plcp[2] = usec & 0xff; ++ plcp[3] = (usec >> 8) & 0xff; ++ /* PLCP CRC16 */ ++ plcp[4] = 0; ++ plcp[5] = 0; ++} ++ ++/* Rate: 802.11 rate code, length: PSDU length in octets */ ++static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp) ++{ ++ u8 mcs = (u8) (rspec & RSPEC_RATE_MASK); ++ plcp[0] = mcs; ++ if (rspec_is40mhz(rspec) || (mcs == 32)) ++ plcp[0] |= MIMO_PLCP_40MHZ; ++ BRCMS_SET_MIMO_PLCP_LEN(plcp, length); ++ plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */ ++ plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */ ++ plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */ ++ plcp[5] = 0; ++} ++ ++/* Rate: 802.11 rate code, length: PSDU length in octets */ ++static void ++brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp) ++{ ++ u8 rate_signal; ++ u32 tmp = 0; ++ int rate = rspec2rate(rspec); ++ ++ /* ++ * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb ++ * transmitted first ++ */ ++ rate_signal = rate_info[rate] & BRCMS_RATE_MASK; ++ memset(plcp, 0, D11_PHY_HDR_LEN); ++ D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal); ++ ++ tmp = (length & 0xfff) << 5; ++ plcp[2] |= (tmp >> 16) & 0xff; ++ plcp[1] |= (tmp >> 8) & 0xff; ++ plcp[0] |= tmp & 0xff; ++} ++ ++/* Rate: 802.11 rate code, length: PSDU length in octets */ ++static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec, ++ uint length, u8 *plcp) ++{ ++ int rate = rspec2rate(rspec); ++ ++ brcms_c_cck_plcp_set(wlc, rate, length, plcp); ++} ++ ++static void ++brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec, ++ uint length, u8 *plcp) ++{ ++ if (is_mcs_rate(rspec)) ++ brcms_c_compute_mimo_plcp(rspec, length, plcp); ++ else if (is_ofdm_rate(rspec)) ++ brcms_c_compute_ofdm_plcp(rspec, length, plcp); ++ else ++ brcms_c_compute_cck_plcp(wlc, rspec, length, plcp); ++} ++ ++/* brcms_c_compute_rtscts_dur() ++ * ++ * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame ++ * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK ++ * DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK ++ * ++ * cts cts-to-self or rts/cts ++ * rts_rate rts or cts rate in unit of 500kbps ++ * rate next MPDU rate in unit of 500kbps ++ * frame_len next MPDU frame length in bytes ++ */ ++u16 ++brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, ++ u32 rts_rate, ++ u32 frame_rate, u8 rts_preamble_type, ++ u8 frame_preamble_type, uint frame_len, bool ba) ++{ ++ u16 dur, sifs; ++ ++ sifs = get_sifs(wlc->band); ++ ++ if (!cts_only) { ++ /* RTS/CTS */ ++ dur = 3 * sifs; ++ dur += ++ (u16) brcms_c_calc_cts_time(wlc, rts_rate, ++ rts_preamble_type); ++ } else { ++ /* CTS-TO-SELF */ ++ dur = 2 * sifs; ++ } ++ ++ dur += ++ (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type, ++ frame_len); ++ if (ba) ++ dur += ++ (u16) brcms_c_calc_ba_time(wlc, frame_rate, ++ BRCMS_SHORT_PREAMBLE); ++ else ++ dur += ++ (u16) brcms_c_calc_ack_time(wlc, frame_rate, ++ frame_preamble_type); ++ return dur; ++} ++ ++static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec) ++{ ++ u16 phyctl1 = 0; ++ u16 bw; ++ ++ if (BRCMS_ISLCNPHY(wlc->band)) { ++ bw = PHY_TXC1_BW_20MHZ; ++ } else { ++ bw = rspec_get_bw(rspec); ++ /* 10Mhz is not supported yet */ ++ if (bw < PHY_TXC1_BW_20MHZ) { ++ wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is " ++ "not supported yet, set to 20L\n", bw); ++ bw = PHY_TXC1_BW_20MHZ; ++ } ++ } ++ ++ if (is_mcs_rate(rspec)) { ++ uint mcs = rspec & RSPEC_RATE_MASK; ++ ++ /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */ ++ phyctl1 = rspec_phytxbyte2(rspec); ++ /* set the upper byte of phyctl1 */ ++ phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8); ++ } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band) ++ && !BRCMS_ISSSLPNPHY(wlc->band)) { ++ /* ++ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK ++ * Data Rate. Eventually MIMOPHY would also be converted to ++ * this format ++ */ ++ /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */ ++ phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT)); ++ } else { /* legacy OFDM/CCK */ ++ s16 phycfg; ++ /* get the phyctl byte from rate phycfg table */ ++ phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec)); ++ if (phycfg == -1) { ++ wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong " ++ "legacy OFDM/CCK rate\n"); ++ phycfg = 0; ++ } ++ /* set the upper byte of phyctl1 */ ++ phyctl1 = ++ (bw | (phycfg << 8) | ++ (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT)); ++ } ++ return phyctl1; ++} ++ ++/* ++ * Add struct d11txh, struct cck_phy_hdr. ++ * ++ * 'p' data must start with 802.11 MAC header ++ * 'p' must allow enough bytes of local headers to be "pushed" onto the packet ++ * ++ * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes) ++ * ++ */ ++static u16 ++brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, ++ struct sk_buff *p, struct scb *scb, uint frag, ++ uint nfrags, uint queue, uint next_frag_len) ++{ ++ struct ieee80211_hdr *h; ++ struct d11txh *txh; ++ u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN]; ++ int len, phylen, rts_phylen; ++ u16 mch, phyctl, xfts, mainrates; ++ u16 seq = 0, mcl = 0, status = 0, frameid = 0; ++ u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }; ++ u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }; ++ bool use_rts = false; ++ bool use_cts = false; ++ bool use_rifs = false; ++ bool short_preamble[2] = { false, false }; ++ u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; ++ u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; ++ u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN]; ++ struct ieee80211_rts *rts = NULL; ++ bool qos; ++ uint ac; ++ bool hwtkmic = false; ++ u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; ++#define ANTCFG_NONE 0xFF ++ u8 antcfg = ANTCFG_NONE; ++ u8 fbantcfg = ANTCFG_NONE; ++ uint phyctl1_stf = 0; ++ u16 durid = 0; ++ struct ieee80211_tx_rate *txrate[2]; ++ int k; ++ struct ieee80211_tx_info *tx_info; ++ bool is_mcs; ++ u16 mimo_txbw; ++ u8 mimo_preamble_type; ++ ++ /* locate 802.11 MAC header */ ++ h = (struct ieee80211_hdr *)(p->data); ++ qos = ieee80211_is_data_qos(h->frame_control); ++ ++ /* compute length of frame in bytes for use in PLCP computations */ ++ len = brcmu_pkttotlen(p); ++ phylen = len + FCS_LEN; ++ ++ /* Get tx_info */ ++ tx_info = IEEE80211_SKB_CB(p); ++ ++ /* add PLCP */ ++ plcp = skb_push(p, D11_PHY_HDR_LEN); ++ ++ /* add Broadcom tx descriptor header */ ++ txh = (struct d11txh *) skb_push(p, D11_TXH_LEN); ++ memset(txh, 0, D11_TXH_LEN); ++ ++ /* setup frameid */ ++ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { ++ /* non-AP STA should never use BCMC queue */ ++ if (queue == TX_BCMC_FIFO) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == " ++ "TX_BCMC!\n", wlc->pub->unit, __func__); ++ frameid = bcmc_fid_generate(wlc, NULL, txh); ++ } else { ++ /* Increment the counter for first fragment */ ++ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) ++ scb->seqnum[p->priority]++; ++ ++ /* extract fragment number from frame first */ ++ seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK; ++ seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT); ++ h->seq_ctrl = cpu_to_le16(seq); ++ ++ frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | ++ (queue & TXFID_QUEUE_MASK); ++ } ++ } ++ frameid |= queue & TXFID_QUEUE_MASK; ++ ++ /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */ ++ if (ieee80211_is_beacon(h->frame_control)) ++ mcl |= TXC_IGNOREPMQ; ++ ++ txrate[0] = tx_info->control.rates; ++ txrate[1] = txrate[0] + 1; ++ ++ /* ++ * if rate control algorithm didn't give us a fallback ++ * rate, use the primary rate ++ */ ++ if (txrate[1]->idx < 0) ++ txrate[1] = txrate[0]; ++ ++ for (k = 0; k < hw->max_rates; k++) { ++ is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false; ++ if (!is_mcs) { ++ if ((txrate[k]->idx >= 0) ++ && (txrate[k]->idx < ++ hw->wiphy->bands[tx_info->band]->n_bitrates)) { ++ rspec[k] = ++ hw->wiphy->bands[tx_info->band]-> ++ bitrates[txrate[k]->idx].hw_value; ++ short_preamble[k] = ++ txrate[k]-> ++ flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ? ++ true : false; ++ } else { ++ rspec[k] = BRCM_RATE_1M; ++ } ++ } else { ++ rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, ++ NRATE_MCS_INUSE | txrate[k]->idx); ++ } ++ ++ /* ++ * Currently only support same setting for primay and ++ * fallback rates. Unify flags for each rate into a ++ * single value for the frame ++ */ ++ use_rts |= ++ txrate[k]-> ++ flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false; ++ use_cts |= ++ txrate[k]-> ++ flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false; ++ ++ ++ /* ++ * (1) RATE: ++ * determine and validate primary rate ++ * and fallback rates ++ */ ++ if (!rspec_active(rspec[k])) { ++ rspec[k] = BRCM_RATE_1M; ++ } else { ++ if (!is_multicast_ether_addr(h->addr1)) { ++ /* set tx antenna config */ ++ brcms_c_antsel_antcfg_get(wlc->asi, false, ++ false, 0, 0, &antcfg, &fbantcfg); ++ } ++ } ++ } ++ ++ phyctl1_stf = wlc->stf->ss_opmode; ++ ++ if (wlc->pub->_n_enab & SUPPORT_11N) { ++ for (k = 0; k < hw->max_rates; k++) { ++ /* ++ * apply siso/cdd to single stream mcs's or ofdm ++ * if rspec is auto selected ++ */ ++ if (((is_mcs_rate(rspec[k]) && ++ is_single_stream(rspec[k] & RSPEC_RATE_MASK)) || ++ is_ofdm_rate(rspec[k])) ++ && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY) ++ || !(rspec[k] & RSPEC_OVERRIDE))) { ++ rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK); ++ ++ /* For SISO MCS use STBC if possible */ ++ if (is_mcs_rate(rspec[k]) ++ && BRCMS_STF_SS_STBC_TX(wlc, scb)) { ++ u8 stc; ++ ++ /* Nss for single stream is always 1 */ ++ stc = 1; ++ rspec[k] |= (PHY_TXC1_MODE_STBC << ++ RSPEC_STF_SHIFT) | ++ (stc << RSPEC_STC_SHIFT); ++ } else ++ rspec[k] |= ++ (phyctl1_stf << RSPEC_STF_SHIFT); ++ } ++ ++ /* ++ * Is the phy configured to use 40MHZ frames? If ++ * so then pick the desired txbw ++ */ ++ if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) { ++ /* default txbw is 20in40 SB */ ++ mimo_ctlchbw = mimo_txbw = ++ CHSPEC_SB_UPPER(wlc_phy_chanspec_get( ++ wlc->band->pi)) ++ ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; ++ ++ if (is_mcs_rate(rspec[k])) { ++ /* mcs 32 must be 40b/w DUP */ ++ if ((rspec[k] & RSPEC_RATE_MASK) ++ == 32) { ++ mimo_txbw = ++ PHY_TXC1_BW_40MHZ_DUP; ++ /* use override */ ++ } else if (wlc->mimo_40txbw != AUTO) ++ mimo_txbw = wlc->mimo_40txbw; ++ /* else check if dst is using 40 Mhz */ ++ else if (scb->flags & SCB_IS40) ++ mimo_txbw = PHY_TXC1_BW_40MHZ; ++ } else if (is_ofdm_rate(rspec[k])) { ++ if (wlc->ofdm_40txbw != AUTO) ++ mimo_txbw = wlc->ofdm_40txbw; ++ } else if (wlc->cck_40txbw != AUTO) { ++ mimo_txbw = wlc->cck_40txbw; ++ } ++ } else { ++ /* ++ * mcs32 is 40 b/w only. ++ * This is possible for probe packets on ++ * a STA during SCAN ++ */ ++ if ((rspec[k] & RSPEC_RATE_MASK) == 32) ++ /* mcs 0 */ ++ rspec[k] = RSPEC_MIMORATE; ++ ++ mimo_txbw = PHY_TXC1_BW_20MHZ; ++ } ++ ++ /* Set channel width */ ++ rspec[k] &= ~RSPEC_BW_MASK; ++ if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k]))) ++ rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT); ++ else ++ rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT); ++ ++ /* Disable short GI, not supported yet */ ++ rspec[k] &= ~RSPEC_SHORT_GI; ++ ++ mimo_preamble_type = BRCMS_MM_PREAMBLE; ++ if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD) ++ mimo_preamble_type = BRCMS_GF_PREAMBLE; ++ ++ if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) ++ && (!is_mcs_rate(rspec[k]))) { ++ wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_" ++ "RC_MCS != is_mcs_rate(rspec)\n", ++ wlc->pub->unit, __func__); ++ } ++ ++ if (is_mcs_rate(rspec[k])) { ++ preamble_type[k] = mimo_preamble_type; ++ ++ /* ++ * if SGI is selected, then forced mm ++ * for single stream ++ */ ++ if ((rspec[k] & RSPEC_SHORT_GI) ++ && is_single_stream(rspec[k] & ++ RSPEC_RATE_MASK)) ++ preamble_type[k] = BRCMS_MM_PREAMBLE; ++ } ++ ++ /* should be better conditionalized */ ++ if (!is_mcs_rate(rspec[0]) ++ && (tx_info->control.rates[0]. ++ flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) ++ preamble_type[k] = BRCMS_SHORT_PREAMBLE; ++ } ++ } else { ++ for (k = 0; k < hw->max_rates; k++) { ++ /* Set ctrlchbw as 20Mhz */ ++ rspec[k] &= ~RSPEC_BW_MASK; ++ rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT); ++ ++ /* for nphy, stf of ofdm frames must follow policies */ ++ if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) { ++ rspec[k] &= ~RSPEC_STF_MASK; ++ rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT; ++ } ++ } ++ } ++ ++ /* Reset these for use with AMPDU's */ ++ txrate[0]->count = 0; ++ txrate[1]->count = 0; ++ ++ /* (2) PROTECTION, may change rspec */ ++ if ((ieee80211_is_data(h->frame_control) || ++ ieee80211_is_mgmt(h->frame_control)) && ++ (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1)) ++ use_rts = true; ++ ++ /* (3) PLCP: determine PLCP header and MAC duration, ++ * fill struct d11txh */ ++ brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp); ++ brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback); ++ memcpy(&txh->FragPLCPFallback, ++ plcp_fallback, sizeof(txh->FragPLCPFallback)); ++ ++ /* Length field now put in CCK FBR CRC field */ ++ if (is_cck_rate(rspec[1])) { ++ txh->FragPLCPFallback[4] = phylen & 0xff; ++ txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8; ++ } ++ ++ /* MIMO-RATE: need validation ?? */ ++ mainrates = is_ofdm_rate(rspec[0]) ? ++ D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) : ++ plcp[0]; ++ ++ /* DUR field for main rate */ ++ if (!ieee80211_is_pspoll(h->frame_control) && ++ !is_multicast_ether_addr(h->addr1) && !use_rifs) { ++ durid = ++ brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0], ++ next_frag_len); ++ h->duration_id = cpu_to_le16(durid); ++ } else if (use_rifs) { ++ /* NAV protect to end of next max packet size */ ++ durid = ++ (u16) brcms_c_calc_frame_time(wlc, rspec[0], ++ preamble_type[0], ++ DOT11_MAX_FRAG_LEN); ++ durid += RIFS_11N_TIME; ++ h->duration_id = cpu_to_le16(durid); ++ } ++ ++ /* DUR field for fallback rate */ ++ if (ieee80211_is_pspoll(h->frame_control)) ++ txh->FragDurFallback = h->duration_id; ++ else if (is_multicast_ether_addr(h->addr1) || use_rifs) ++ txh->FragDurFallback = 0; ++ else { ++ durid = brcms_c_compute_frame_dur(wlc, rspec[1], ++ preamble_type[1], next_frag_len); ++ txh->FragDurFallback = cpu_to_le16(durid); ++ } ++ ++ /* (4) MAC-HDR: MacTxControlLow */ ++ if (frag == 0) ++ mcl |= TXC_STARTMSDU; ++ ++ if (!is_multicast_ether_addr(h->addr1)) ++ mcl |= TXC_IMMEDACK; ++ ++ if (wlc->band->bandtype == BRCM_BAND_5G) ++ mcl |= TXC_FREQBAND_5G; ++ ++ if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi))) ++ mcl |= TXC_BW_40; ++ ++ /* set AMIC bit if using hardware TKIP MIC */ ++ if (hwtkmic) ++ mcl |= TXC_AMIC; ++ ++ txh->MacTxControlLow = cpu_to_le16(mcl); ++ ++ /* MacTxControlHigh */ ++ mch = 0; ++ ++ /* Set fallback rate preamble type */ ++ if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) || ++ (preamble_type[1] == BRCMS_GF_PREAMBLE)) { ++ if (rspec2rate(rspec[1]) != BRCM_RATE_1M) ++ mch |= TXC_PREAMBLE_DATA_FB_SHORT; ++ } ++ ++ /* MacFrameControl */ ++ memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16)); ++ txh->TxFesTimeNormal = cpu_to_le16(0); ++ ++ txh->TxFesTimeFallback = cpu_to_le16(0); ++ ++ /* TxFrameRA */ ++ memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN); ++ ++ /* TxFrameID */ ++ txh->TxFrameID = cpu_to_le16(frameid); ++ ++ /* ++ * TxStatus, Note the case of recreating the first frag of a suppressed ++ * frame then we may need to reset the retry cnt's via the status reg ++ */ ++ txh->TxStatus = cpu_to_le16(status); ++ ++ /* ++ * extra fields for ucode AMPDU aggregation, the new fields are added to ++ * the END of previous structure so that it's compatible in driver. ++ */ ++ txh->MaxNMpdus = cpu_to_le16(0); ++ txh->MaxABytes_MRT = cpu_to_le16(0); ++ txh->MaxABytes_FBR = cpu_to_le16(0); ++ txh->MinMBytes = cpu_to_le16(0); ++ ++ /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration, ++ * furnish struct d11txh */ ++ /* RTS PLCP header and RTS frame */ ++ if (use_rts || use_cts) { ++ if (use_rts && use_cts) ++ use_cts = false; ++ ++ for (k = 0; k < 2; k++) { ++ rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k], ++ false, ++ mimo_ctlchbw); ++ } ++ ++ if (!is_ofdm_rate(rts_rspec[0]) && ++ !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) || ++ (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { ++ rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE; ++ mch |= TXC_PREAMBLE_RTS_MAIN_SHORT; ++ } ++ ++ if (!is_ofdm_rate(rts_rspec[1]) && ++ !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) || ++ (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { ++ rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE; ++ mch |= TXC_PREAMBLE_RTS_FB_SHORT; ++ } ++ ++ /* RTS/CTS additions to MacTxControlLow */ ++ if (use_cts) { ++ txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS); ++ } else { ++ txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS); ++ txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME); ++ } ++ ++ /* RTS PLCP header */ ++ rts_plcp = txh->RTSPhyHeader; ++ if (use_cts) ++ rts_phylen = DOT11_CTS_LEN + FCS_LEN; ++ else ++ rts_phylen = DOT11_RTS_LEN + FCS_LEN; ++ ++ brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp); ++ ++ /* fallback rate version of RTS PLCP header */ ++ brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen, ++ rts_plcp_fallback); ++ memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback, ++ sizeof(txh->RTSPLCPFallback)); ++ ++ /* RTS frame fields... */ ++ rts = (struct ieee80211_rts *)&txh->rts_frame; ++ ++ durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0], ++ rspec[0], rts_preamble_type[0], ++ preamble_type[0], phylen, false); ++ rts->duration = cpu_to_le16(durid); ++ /* fallback rate version of RTS DUR field */ ++ durid = brcms_c_compute_rtscts_dur(wlc, use_cts, ++ rts_rspec[1], rspec[1], ++ rts_preamble_type[1], ++ preamble_type[1], phylen, false); ++ txh->RTSDurFallback = cpu_to_le16(durid); ++ ++ if (use_cts) { ++ rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | ++ IEEE80211_STYPE_CTS); ++ ++ memcpy(&rts->ra, &h->addr2, ETH_ALEN); ++ } else { ++ rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | ++ IEEE80211_STYPE_RTS); ++ ++ memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN); ++ } ++ ++ /* mainrate ++ * low 8 bits: main frag rate/mcs, ++ * high 8 bits: rts/cts rate/mcs ++ */ ++ mainrates |= (is_ofdm_rate(rts_rspec[0]) ? ++ D11A_PHY_HDR_GRATE( ++ (struct ofdm_phy_hdr *) rts_plcp) : ++ rts_plcp[0]) << 8; ++ } else { ++ memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); ++ memset((char *)&txh->rts_frame, 0, ++ sizeof(struct ieee80211_rts)); ++ memset((char *)txh->RTSPLCPFallback, 0, ++ sizeof(txh->RTSPLCPFallback)); ++ txh->RTSDurFallback = 0; ++ } ++ ++#ifdef SUPPORT_40MHZ ++ /* add null delimiter count */ ++ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec)) ++ txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = ++ brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen); ++ ++#endif ++ ++ /* ++ * Now that RTS/RTS FB preamble types are updated, write ++ * the final value ++ */ ++ txh->MacTxControlHigh = cpu_to_le16(mch); ++ ++ /* ++ * MainRates (both the rts and frag plcp rates have ++ * been calculated now) ++ */ ++ txh->MainRates = cpu_to_le16(mainrates); ++ ++ /* XtraFrameTypes */ ++ xfts = frametype(rspec[1], wlc->mimoft); ++ xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT); ++ xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT); ++ xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) << ++ XFTS_CHANNEL_SHIFT; ++ txh->XtraFrameTypes = cpu_to_le16(xfts); ++ ++ /* PhyTxControlWord */ ++ phyctl = frametype(rspec[0], wlc->mimoft); ++ if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) || ++ (preamble_type[0] == BRCMS_GF_PREAMBLE)) { ++ if (rspec2rate(rspec[0]) != BRCM_RATE_1M) ++ phyctl |= PHY_TXC_SHORT_HDR; ++ } ++ ++ /* phytxant is properly bit shifted */ ++ phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]); ++ txh->PhyTxControlWord = cpu_to_le16(phyctl); ++ ++ /* PhyTxControlWord_1 */ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) { ++ u16 phyctl1 = 0; ++ ++ phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]); ++ txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1); ++ phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]); ++ txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1); ++ ++ if (use_rts || use_cts) { ++ phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]); ++ txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1); ++ phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]); ++ txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1); ++ } ++ ++ /* ++ * For mcs frames, if mixedmode(overloaded with long preamble) ++ * is going to be set, fill in non-zero MModeLen and/or ++ * MModeFbrLen it will be unnecessary if they are separated ++ */ ++ if (is_mcs_rate(rspec[0]) && ++ (preamble_type[0] == BRCMS_MM_PREAMBLE)) { ++ u16 mmodelen = ++ brcms_c_calc_lsig_len(wlc, rspec[0], phylen); ++ txh->MModeLen = cpu_to_le16(mmodelen); ++ } ++ ++ if (is_mcs_rate(rspec[1]) && ++ (preamble_type[1] == BRCMS_MM_PREAMBLE)) { ++ u16 mmodefbrlen = ++ brcms_c_calc_lsig_len(wlc, rspec[1], phylen); ++ txh->MModeFbrLen = cpu_to_le16(mmodefbrlen); ++ } ++ } ++ ++ ac = skb_get_queue_mapping(p); ++ if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) { ++ uint frag_dur, dur, dur_fallback; ++ ++ /* WME: Update TXOP threshold */ ++ if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) { ++ frag_dur = ++ brcms_c_calc_frame_time(wlc, rspec[0], ++ preamble_type[0], phylen); ++ ++ if (rts) { ++ /* 1 RTS or CTS-to-self frame */ ++ dur = ++ brcms_c_calc_cts_time(wlc, rts_rspec[0], ++ rts_preamble_type[0]); ++ dur_fallback = ++ brcms_c_calc_cts_time(wlc, rts_rspec[1], ++ rts_preamble_type[1]); ++ /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */ ++ dur += le16_to_cpu(rts->duration); ++ dur_fallback += ++ le16_to_cpu(txh->RTSDurFallback); ++ } else if (use_rifs) { ++ dur = frag_dur; ++ dur_fallback = 0; ++ } else { ++ /* frame + SIFS + ACK */ ++ dur = frag_dur; ++ dur += ++ brcms_c_compute_frame_dur(wlc, rspec[0], ++ preamble_type[0], 0); ++ ++ dur_fallback = ++ brcms_c_calc_frame_time(wlc, rspec[1], ++ preamble_type[1], ++ phylen); ++ dur_fallback += ++ brcms_c_compute_frame_dur(wlc, rspec[1], ++ preamble_type[1], 0); ++ } ++ /* NEED to set TxFesTimeNormal (hard) */ ++ txh->TxFesTimeNormal = cpu_to_le16((u16) dur); ++ /* ++ * NEED to set fallback rate version of ++ * TxFesTimeNormal (hard) ++ */ ++ txh->TxFesTimeFallback = ++ cpu_to_le16((u16) dur_fallback); ++ ++ /* ++ * update txop byte threshold (txop minus intraframe ++ * overhead) ++ */ ++ if (wlc->edcf_txop[ac] >= (dur - frag_dur)) { ++ uint newfragthresh; ++ ++ newfragthresh = ++ brcms_c_calc_frame_len(wlc, ++ rspec[0], preamble_type[0], ++ (wlc->edcf_txop[ac] - ++ (dur - frag_dur))); ++ /* range bound the fragthreshold */ ++ if (newfragthresh < DOT11_MIN_FRAG_LEN) ++ newfragthresh = ++ DOT11_MIN_FRAG_LEN; ++ else if (newfragthresh > ++ wlc->usr_fragthresh) ++ newfragthresh = ++ wlc->usr_fragthresh; ++ /* update the fragthresh and do txc update */ ++ if (wlc->fragthresh[queue] != ++ (u16) newfragthresh) ++ wlc->fragthresh[queue] = ++ (u16) newfragthresh; ++ } else { ++ wiphy_err(wlc->wiphy, "wl%d: %s txop invalid " ++ "for rate %d\n", ++ wlc->pub->unit, fifo_names[queue], ++ rspec2rate(rspec[0])); ++ } ++ ++ if (dur > wlc->edcf_txop[ac]) ++ wiphy_err(wlc->wiphy, "wl%d: %s: %s txop " ++ "exceeded phylen %d/%d dur %d/%d\n", ++ wlc->pub->unit, __func__, ++ fifo_names[queue], ++ phylen, wlc->fragthresh[queue], ++ dur, wlc->edcf_txop[ac]); ++ } ++ } ++ ++ return 0; ++} ++ ++void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, ++ struct ieee80211_hw *hw) ++{ ++ u8 prio; ++ uint fifo; ++ struct scb *scb = &wlc->pri_scb; ++ struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data); ++ ++ /* ++ * 802.11 standard requires management traffic ++ * to go at highest priority ++ */ ++ prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority : ++ MAXPRIO; ++ fifo = prio2fifo[prio]; ++ if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0)) ++ return; ++ brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio)); ++ brcms_c_send_q(wlc); ++} ++ ++void brcms_c_send_q(struct brcms_c_info *wlc) ++{ ++ struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; ++ int prec; ++ u16 prec_map; ++ int err = 0, i, count; ++ uint fifo; ++ struct brcms_txq_info *qi = wlc->pkt_queue; ++ struct pktq *q = &qi->q; ++ struct ieee80211_tx_info *tx_info; ++ ++ prec_map = wlc->tx_prec_map; ++ ++ /* Send all the enq'd pkts that we can. ++ * Dequeue packets with precedence with empty HW fifo only ++ */ ++ while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) { ++ tx_info = IEEE80211_SKB_CB(pkt[0]); ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { ++ err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec); ++ } else { ++ count = 1; ++ err = brcms_c_prep_pdu(wlc, pkt[0], &fifo); ++ if (!err) { ++ for (i = 0; i < count; i++) ++ brcms_c_txfifo(wlc, fifo, pkt[i], true, ++ 1); ++ } ++ } ++ ++ if (err == -EBUSY) { ++ brcmu_pktq_penq_head(q, prec, pkt[0]); ++ /* ++ * If send failed due to any other reason than a ++ * change in HW FIFO condition, quit. Otherwise, ++ * read the new prec_map! ++ */ ++ if (prec_map == wlc->tx_prec_map) ++ break; ++ prec_map = wlc->tx_prec_map; ++ } ++ } ++} ++ ++void ++brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, ++ bool commit, s8 txpktpend) ++{ ++ u16 frameid = INVALIDFID; ++ struct d11txh *txh; ++ ++ txh = (struct d11txh *) (p->data); ++ ++ /* When a BC/MC frame is being committed to the BCMC fifo ++ * via DMA (NOT PIO), update ucode or BSS info as appropriate. ++ */ ++ if (fifo == TX_BCMC_FIFO) ++ frameid = le16_to_cpu(txh->TxFrameID); ++ ++ /* ++ * Bump up pending count for if not using rpc. If rpc is ++ * used, this will be handled in brcms_b_txfifo() ++ */ ++ if (commit) { ++ wlc->core->txpktpend[fifo] += txpktpend; ++ BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n", ++ txpktpend, wlc->core->txpktpend[fifo]); ++ } ++ ++ /* Commit BCMC sequence number in the SHM frame ID location */ ++ if (frameid != INVALIDFID) { ++ /* ++ * To inform the ucode of the last mcast frame posted ++ * so that it can clear moredata bit ++ */ ++ brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid); ++ } ++ ++ if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) ++ wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n"); ++} ++ ++u32 ++brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec, ++ bool use_rspec, u16 mimo_ctlchbw) ++{ ++ u32 rts_rspec = 0; ++ ++ if (use_rspec) ++ /* use frame rate as rts rate */ ++ rts_rspec = rspec; ++ else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec)) ++ /* Use 11Mbps as the g protection RTS target rate and fallback. ++ * Use the brcms_basic_rate() lookup to find the best basic rate ++ * under the target in case 11 Mbps is not Basic. ++ * 6 and 9 Mbps are not usually selected by rate selection, but ++ * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11 ++ * is more robust. ++ */ ++ rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M); ++ else ++ /* calculate RTS rate and fallback rate based on the frame rate ++ * RTS must be sent at a basic rate since it is a ++ * control frame, sec 9.6 of 802.11 spec ++ */ ++ rts_rspec = brcms_basic_rate(wlc, rspec); ++ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) { ++ /* set rts txbw to correct side band */ ++ rts_rspec &= ~RSPEC_BW_MASK; ++ ++ /* ++ * if rspec/rspec_fallback is 40MHz, then send RTS on both ++ * 20MHz channel (DUP), otherwise send RTS on control channel ++ */ ++ if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec)) ++ rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT); ++ else ++ rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT); ++ ++ /* pick siso/cdd as default for ofdm */ ++ if (is_ofdm_rate(rts_rspec)) { ++ rts_rspec &= ~RSPEC_STF_MASK; ++ rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT); ++ } ++ } ++ return rts_rspec; ++} ++ ++void ++brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend) ++{ ++ wlc->core->txpktpend[fifo] -= txpktpend; ++ BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend, ++ wlc->core->txpktpend[fifo]); ++ ++ /* There is more room; mark precedences related to this FIFO sendable */ ++ wlc->tx_prec_map |= wlc->fifo2prec_map[fifo]; ++ ++ /* figure out which bsscfg is being worked on... */ ++} ++ ++/* Update beacon listen interval in shared memory */ ++static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc) ++{ ++ /* wake up every DTIM is the default */ ++ if (wlc->bcn_li_dtim == 1) ++ brcms_b_write_shm(wlc->hw, M_BCN_LI, 0); ++ else ++ brcms_b_write_shm(wlc->hw, M_BCN_LI, ++ (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn); ++} ++ ++static void ++brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr, ++ u32 *tsf_h_ptr) ++{ ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ ++ /* read the tsf timer low, then high to get an atomic read */ ++ *tsf_l_ptr = R_REG(®s->tsf_timerlow); ++ *tsf_h_ptr = R_REG(®s->tsf_timerhigh); ++} ++ ++/* ++ * recover 64bit TSF value from the 16bit TSF value in the rx header ++ * given the assumption that the TSF passed in header is within 65ms ++ * of the current tsf. ++ * ++ * 6 5 4 4 3 2 1 ++ * 3.......6.......8.......0.......2.......4.......6.......8......0 ++ * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->| ++ * ++ * The RxTSFTime are the lowest 16 bits and provided by the ucode. The ++ * tsf_l is filled in by brcms_b_recv, which is done earlier in the ++ * receive call sequence after rx interrupt. Only the higher 16 bits ++ * are used. Finally, the tsf_h is read from the tsf register. ++ */ ++static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc, ++ struct d11rxhdr *rxh) ++{ ++ u32 tsf_h, tsf_l; ++ u16 rx_tsf_0_15, rx_tsf_16_31; ++ ++ brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h); ++ ++ rx_tsf_16_31 = (u16)(tsf_l >> 16); ++ rx_tsf_0_15 = rxh->RxTSFTime; ++ ++ /* ++ * a greater tsf time indicates the low 16 bits of ++ * tsf_l wrapped, so decrement the high 16 bits. ++ */ ++ if ((u16)tsf_l < rx_tsf_0_15) { ++ rx_tsf_16_31 -= 1; ++ if (rx_tsf_16_31 == 0xffff) ++ tsf_h -= 1; ++ } ++ ++ return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15); ++} ++ ++static void ++prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, ++ struct sk_buff *p, ++ struct ieee80211_rx_status *rx_status) ++{ ++ int preamble; ++ int channel; ++ u32 rspec; ++ unsigned char *plcp; ++ ++ /* fill in TSF and flag its presence */ ++ rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh); ++ rx_status->flag |= RX_FLAG_MACTIME_MPDU; ++ ++ channel = BRCMS_CHAN_CHANNEL(rxh->RxChan); ++ ++ if (channel > 14) { ++ rx_status->band = IEEE80211_BAND_5GHZ; ++ rx_status->freq = ieee80211_ofdm_chan_to_freq( ++ WF_CHAN_FACTOR_5_G/2, channel); ++ ++ } else { ++ rx_status->band = IEEE80211_BAND_2GHZ; ++ rx_status->freq = ieee80211_dsss_chan_to_freq(channel); ++ } ++ ++ rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh); ++ ++ /* noise */ ++ /* qual */ ++ rx_status->antenna = ++ (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; ++ ++ plcp = p->data; ++ ++ rspec = brcms_c_compute_rspec(rxh, plcp); ++ if (is_mcs_rate(rspec)) { ++ rx_status->rate_idx = rspec & RSPEC_RATE_MASK; ++ rx_status->flag |= RX_FLAG_HT; ++ if (rspec_is40mhz(rspec)) ++ rx_status->flag |= RX_FLAG_40MHZ; ++ } else { ++ switch (rspec2rate(rspec)) { ++ case BRCM_RATE_1M: ++ rx_status->rate_idx = 0; ++ break; ++ case BRCM_RATE_2M: ++ rx_status->rate_idx = 1; ++ break; ++ case BRCM_RATE_5M5: ++ rx_status->rate_idx = 2; ++ break; ++ case BRCM_RATE_11M: ++ rx_status->rate_idx = 3; ++ break; ++ case BRCM_RATE_6M: ++ rx_status->rate_idx = 4; ++ break; ++ case BRCM_RATE_9M: ++ rx_status->rate_idx = 5; ++ break; ++ case BRCM_RATE_12M: ++ rx_status->rate_idx = 6; ++ break; ++ case BRCM_RATE_18M: ++ rx_status->rate_idx = 7; ++ break; ++ case BRCM_RATE_24M: ++ rx_status->rate_idx = 8; ++ break; ++ case BRCM_RATE_36M: ++ rx_status->rate_idx = 9; ++ break; ++ case BRCM_RATE_48M: ++ rx_status->rate_idx = 10; ++ break; ++ case BRCM_RATE_54M: ++ rx_status->rate_idx = 11; ++ break; ++ default: ++ wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__); ++ } ++ ++ /* ++ * For 5GHz, we should decrease the index as it is ++ * a subset of the 2.4G rates. See bitrates field ++ * of brcms_band_5GHz_nphy (in mac80211_if.c). ++ */ ++ if (rx_status->band == IEEE80211_BAND_5GHZ) ++ rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET; ++ ++ /* Determine short preamble and rate_idx */ ++ preamble = 0; ++ if (is_cck_rate(rspec)) { ++ if (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ++ rx_status->flag |= RX_FLAG_SHORTPRE; ++ } else if (is_ofdm_rate(rspec)) { ++ rx_status->flag |= RX_FLAG_SHORTPRE; ++ } else { ++ wiphy_err(wlc->wiphy, "%s: Unknown modulation\n", ++ __func__); ++ } ++ } ++ ++ if (plcp3_issgi(plcp[3])) ++ rx_status->flag |= RX_FLAG_SHORT_GI; ++ ++ if (rxh->RxStatus1 & RXS_DECERR) { ++ rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; ++ wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n", ++ __func__); ++ } ++ if (rxh->RxStatus1 & RXS_FCSERR) { ++ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; ++ wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n", ++ __func__); ++ } ++} ++ ++static void ++brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh, ++ struct sk_buff *p) ++{ ++ int len_mpdu; ++ struct ieee80211_rx_status rx_status; ++ ++ memset(&rx_status, 0, sizeof(rx_status)); ++ prep_mac80211_status(wlc, rxh, p, &rx_status); ++ ++ /* mac header+body length, exclude CRC and plcp header */ ++ len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN; ++ skb_pull(p, D11_PHY_HDR_LEN); ++ __skb_trim(p, len_mpdu); ++ ++ memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status)); ++ ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); ++} ++ ++/* calculate frame duration for Mixed-mode L-SIG spoofing, return ++ * number of bytes goes in the length field ++ * ++ * Formula given by HT PHY Spec v 1.13 ++ * len = 3(nsyms + nstream + 3) - 3 ++ */ ++u16 ++brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, ++ uint mac_len) ++{ ++ uint nsyms, len = 0, kNdps; ++ ++ BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n", ++ wlc->pub->unit, rspec2rate(ratespec), mac_len); ++ ++ if (is_mcs_rate(ratespec)) { ++ uint mcs = ratespec & RSPEC_RATE_MASK; ++ int tot_streams = (mcs_2_txstreams(mcs) + 1) + ++ rspec_stc(ratespec); ++ ++ /* ++ * the payload duration calculation matches that ++ * of regular ofdm ++ */ ++ /* 1000Ndbps = kbps * 4 */ ++ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), ++ rspec_issgi(ratespec)) * 4; ++ ++ if (rspec_stc(ratespec) == 0) ++ nsyms = ++ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + ++ APHY_TAIL_NBITS) * 1000, kNdps); ++ else ++ /* STBC needs to have even number of symbols */ ++ nsyms = ++ 2 * ++ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + ++ APHY_TAIL_NBITS) * 1000, 2 * kNdps); ++ ++ /* (+3) account for HT-SIG(2) and HT-STF(1) */ ++ nsyms += (tot_streams + 3); ++ /* ++ * 3 bytes/symbol @ legacy 6Mbps rate ++ * (-3) excluding service bits and tail bits ++ */ ++ len = (3 * nsyms) - 3; ++ } ++ ++ return (u16) len; ++} ++ ++static void ++brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len) ++{ ++ const struct brcms_c_rateset *rs_dflt; ++ struct brcms_c_rateset rs; ++ u8 rate; ++ u16 entry_ptr; ++ u8 plcp[D11_PHY_HDR_LEN]; ++ u16 dur, sifs; ++ uint i; ++ ++ sifs = get_sifs(wlc->band); ++ ++ rs_dflt = brcms_c_rateset_get_hwrs(wlc); ++ ++ brcms_c_rateset_copy(rs_dflt, &rs); ++ brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); ++ ++ /* ++ * walk the phy rate table and update MAC core SHM ++ * basic rate table entries ++ */ ++ for (i = 0; i < rs.count; i++) { ++ rate = rs.rates[i] & BRCMS_RATE_MASK; ++ ++ entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate); ++ ++ /* Calculate the Probe Response PLCP for the given rate */ ++ brcms_c_compute_plcp(wlc, rate, frame_len, plcp); ++ ++ /* ++ * Calculate the duration of the Probe Response ++ * frame plus SIFS for the MAC ++ */ ++ dur = (u16) brcms_c_calc_frame_time(wlc, rate, ++ BRCMS_LONG_PREAMBLE, frame_len); ++ dur += sifs; ++ ++ /* Update the SHM Rate Table entry Probe Response values */ ++ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS, ++ (u16) (plcp[0] + (plcp[1] << 8))); ++ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2, ++ (u16) (plcp[2] + (plcp[3] << 8))); ++ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur); ++ } ++} ++ ++/* Max buffering needed for beacon template/prb resp template is 142 bytes. ++ * ++ * PLCP header is 6 bytes. ++ * 802.11 A3 header is 24 bytes. ++ * Max beacon frame body template length is 112 bytes. ++ * Max probe resp frame body template length is 110 bytes. ++ * ++ * *len on input contains the max length of the packet available. ++ * ++ * The *len value is set to the number of bytes in buf used, and starts ++ * with the PLCP and included up to, but not including, the 4 byte FCS. ++ */ ++static void ++brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, ++ u32 bcn_rspec, ++ struct brcms_bss_cfg *cfg, u16 *buf, int *len) ++{ ++ static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; ++ struct cck_phy_hdr *plcp; ++ struct ieee80211_mgmt *h; ++ int hdr_len, body_len; ++ ++ hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN; ++ ++ /* calc buffer size provided for frame body */ ++ body_len = *len - hdr_len; ++ /* return actual size */ ++ *len = hdr_len + body_len; ++ ++ /* format PHY and MAC headers */ ++ memset((char *)buf, 0, hdr_len); ++ ++ plcp = (struct cck_phy_hdr *) buf; ++ ++ /* ++ * PLCP for Probe Response frames are filled in from ++ * core's rate table ++ */ ++ if (type == IEEE80211_STYPE_BEACON) ++ /* fill in PLCP */ ++ brcms_c_compute_plcp(wlc, bcn_rspec, ++ (DOT11_MAC_HDR_LEN + body_len + FCS_LEN), ++ (u8 *) plcp); ++ ++ /* "Regular" and 16 MBSS but not for 4 MBSS */ ++ /* Update the phytxctl for the beacon based on the rspec */ ++ brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec); ++ ++ h = (struct ieee80211_mgmt *)&plcp[1]; ++ ++ /* fill in 802.11 header */ ++ h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type); ++ ++ /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */ ++ /* A1 filled in by MAC for prb resp, broadcast for bcn */ ++ if (type == IEEE80211_STYPE_BEACON) ++ memcpy(&h->da, ðer_bcast, ETH_ALEN); ++ memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN); ++ memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN); ++ ++ /* SEQ filled in by MAC */ ++} ++ ++int brcms_c_get_header_len(void) ++{ ++ return TXOFF; ++} ++ ++/* ++ * Update all beacons for the system. ++ */ ++void brcms_c_update_beacon(struct brcms_c_info *wlc) ++{ ++ struct brcms_bss_cfg *bsscfg = wlc->bsscfg; ++ ++ if (bsscfg->up && !bsscfg->BSS) ++ /* Clear the soft intmask */ ++ wlc->defmacintmask &= ~MI_BCNTPL; ++} ++ ++/* Write ssid into shared memory */ ++static void ++brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg) ++{ ++ u8 *ssidptr = cfg->SSID; ++ u16 base = M_SSID; ++ u8 ssidbuf[IEEE80211_MAX_SSID_LEN]; ++ ++ /* padding the ssid with zero and copy it into shm */ ++ memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN); ++ memcpy(ssidbuf, ssidptr, cfg->SSID_len); ++ ++ brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN); ++ brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len); ++} ++ ++static void ++brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, ++ struct brcms_bss_cfg *cfg, ++ bool suspend) ++{ ++ u16 prb_resp[BCN_TMPL_LEN / 2]; ++ int len = BCN_TMPL_LEN; ++ ++ /* ++ * write the probe response to hardware, or save in ++ * the config structure ++ */ ++ ++ /* create the probe response template */ ++ brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0, ++ cfg, prb_resp, &len); ++ ++ if (suspend) ++ brcms_c_suspend_mac_and_wait(wlc); ++ ++ /* write the probe response into the template region */ ++ brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE, ++ (len + 3) & ~3, prb_resp); ++ ++ /* write the length of the probe response frame (+PLCP/-FCS) */ ++ brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len); ++ ++ /* write the SSID and SSID length */ ++ brcms_c_shm_ssid_upd(wlc, cfg); ++ ++ /* ++ * Write PLCP headers and durations for probe response frames ++ * at all rates. Use the actual frame length covered by the ++ * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table() ++ * by subtracting the PLCP len and adding the FCS. ++ */ ++ len += (-D11_PHY_HDR_LEN + FCS_LEN); ++ brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len); ++ ++ if (suspend) ++ brcms_c_enable_mac(wlc); ++} ++ ++void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) ++{ ++ struct brcms_bss_cfg *bsscfg = wlc->bsscfg; ++ ++ /* update AP or IBSS probe responses */ ++ if (bsscfg->up && !bsscfg->BSS) ++ brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend); ++} ++ ++/* prepares pdu for transmission. returns BCM error codes */ ++int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop) ++{ ++ uint fifo; ++ struct d11txh *txh; ++ struct ieee80211_hdr *h; ++ struct scb *scb; ++ ++ txh = (struct d11txh *) (pdu->data); ++ h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); ++ ++ /* get the pkt queue info. This was put at brcms_c_sendctl or ++ * brcms_c_send for PDU */ ++ fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; ++ ++ scb = NULL; ++ ++ *fifop = fifo; ++ ++ /* return if insufficient dma resources */ ++ if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) { ++ /* Mark precedences related to this FIFO, unsendable */ ++ /* A fifo is full. Clear precedences related to that FIFO */ ++ wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]); ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, ++ uint *blocks) ++{ ++ if (fifo >= NFIFO) ++ return -EINVAL; ++ ++ *blocks = wlc_hw->xmtfifo_sz[fifo]; ++ ++ return 0; ++} ++ ++void ++brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset, ++ const u8 *addr) ++{ ++ brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr); ++ if (match_reg_offset == RCM_BSSID_OFFSET) ++ memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN); ++} ++ ++/* ++ * Flag 'scan in progress' to withhold dynamic phy calibration ++ */ ++void brcms_c_scan_start(struct brcms_c_info *wlc) ++{ ++ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true); ++} ++ ++void brcms_c_scan_stop(struct brcms_c_info *wlc) ++{ ++ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false); ++} ++ ++void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state) ++{ ++ wlc->pub->associated = state; ++ wlc->bsscfg->associated = state; ++} ++ ++/* ++ * When a remote STA/AP is removed by Mac80211, or when it can no longer accept ++ * AMPDU traffic, packets pending in hardware have to be invalidated so that ++ * when later on hardware releases them, they can be handled appropriately. ++ */ ++void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, ++ struct ieee80211_sta *sta, ++ void (*dma_callback_fn)) ++{ ++ struct dma_pub *dmah; ++ int i; ++ for (i = 0; i < NFIFO; i++) { ++ dmah = hw->di[i]; ++ if (dmah != NULL) ++ dma_walk_packets(dmah, dma_callback_fn, sta); ++ } ++} ++ ++int brcms_c_get_curband(struct brcms_c_info *wlc) ++{ ++ return wlc->band->bandunit; ++} ++ ++void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) ++{ ++ /* flush packet queue when requested */ ++ if (drop) ++ brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL); ++ ++ /* wait for queue and DMA fifos to run dry */ ++ while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0) ++ brcms_msleep(wlc->wl, 1); ++} ++ ++void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) ++{ ++ wlc->bcn_li_bcn = interval; ++ if (wlc->pub->up) ++ brcms_c_bcn_li_upd(wlc); ++} ++ ++int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr) ++{ ++ uint qdbm; ++ ++ /* Remove override bit and clip to max qdbm value */ ++ qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff); ++ return wlc_phy_txpower_set(wlc->band->pi, qdbm, false); ++} ++ ++int brcms_c_get_tx_power(struct brcms_c_info *wlc) ++{ ++ uint qdbm; ++ bool override; ++ ++ wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override); ++ ++ /* Return qdbm units */ ++ return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR); ++} ++ ++void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc) ++{ ++ wlc->mpc = mpc; ++ brcms_c_radio_mpc_upd(wlc); ++} ++ ++/* Process received frames */ ++/* ++ * Return true if more frames need to be processed. false otherwise. ++ * Param 'bound' indicates max. # frames to process before break out. ++ */ ++static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) ++{ ++ struct d11rxhdr *rxh; ++ struct ieee80211_hdr *h; ++ uint len; ++ bool is_amsdu; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ /* frame starts with rxhdr */ ++ rxh = (struct d11rxhdr *) (p->data); ++ ++ /* strip off rxhdr */ ++ skb_pull(p, BRCMS_HWRXOFF); ++ ++ /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */ ++ if (rxh->RxStatus1 & RXS_PBPRES) { ++ if (p->len < 2) { ++ wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of " ++ "len %d\n", wlc->pub->unit, p->len); ++ goto toss; ++ } ++ skb_pull(p, 2); ++ } ++ ++ h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN); ++ len = p->len; ++ ++ if (rxh->RxStatus1 & RXS_FCSERR) { ++ if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { ++ wiphy_err(wlc->wiphy, "FCSERR while scanning******* -" ++ " tossing\n"); ++ goto toss; ++ } else { ++ wiphy_err(wlc->wiphy, "RCSERR!!!\n"); ++ goto toss; ++ } ++ } ++ ++ /* check received pkt has at least frame control field */ ++ if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control)) ++ goto toss; ++ ++ /* not supporting A-MSDU */ ++ is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK; ++ if (is_amsdu) ++ goto toss; ++ ++ brcms_c_recvctl(wlc, rxh, p); ++ return; ++ ++ toss: ++ brcmu_pkt_buf_free_skb(p); ++} ++ ++/* Process received frames */ ++/* ++ * Return true if more frames need to be processed. false otherwise. ++ * Param 'bound' indicates max. # frames to process before break out. ++ */ ++static bool ++brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) ++{ ++ struct sk_buff *p; ++ struct sk_buff *head = NULL; ++ struct sk_buff *tail = NULL; ++ uint n = 0; ++ uint bound_limit = bound ? RXBND : -1; ++ ++ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); ++ /* gather received frames */ ++ while ((p = dma_rx(wlc_hw->di[fifo]))) { ++ ++ if (!tail) ++ head = tail = p; ++ else { ++ tail->prev = p; ++ tail = p; ++ } ++ ++ /* !give others some time to run! */ ++ if (++n >= bound_limit) ++ break; ++ } ++ ++ /* post more rbufs */ ++ dma_rxfill(wlc_hw->di[fifo]); ++ ++ /* process each frame */ ++ while ((p = head) != NULL) { ++ struct d11rxhdr_le *rxh_le; ++ struct d11rxhdr *rxh; ++ head = head->prev; ++ p->prev = NULL; ++ ++ rxh_le = (struct d11rxhdr_le *)p->data; ++ rxh = (struct d11rxhdr *)p->data; ++ ++ /* fixup rx header endianness */ ++ rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize); ++ rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0); ++ rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1); ++ rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2); ++ rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3); ++ rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4); ++ rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5); ++ rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1); ++ rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2); ++ rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime); ++ rxh->RxChan = le16_to_cpu(rxh_le->RxChan); ++ ++ brcms_c_recv(wlc_hw->wlc, p); ++ } ++ ++ return n >= bound_limit; ++} ++ ++/* second-level interrupt processing ++ * Return true if another dpc needs to be re-scheduled. false otherwise. ++ * Param 'bounded' indicates if applicable loops should be bounded. ++ */ ++bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) ++{ ++ u32 macintstatus; ++ struct brcms_hardware *wlc_hw = wlc->hw; ++ struct d11regs __iomem *regs = wlc_hw->regs; ++ struct wiphy *wiphy = wlc->wiphy; ++ ++ if (brcms_deviceremoved(wlc)) { ++ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, ++ __func__); ++ brcms_down(wlc->wl); ++ return false; ++ } ++ ++ /* grab and clear the saved software intstatus bits */ ++ macintstatus = wlc->macintstatus; ++ wlc->macintstatus = 0; ++ ++ BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n", ++ wlc_hw->unit, macintstatus); ++ ++ WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */ ++ ++ /* tx status */ ++ if (macintstatus & MI_TFS) { ++ bool fatal; ++ if (brcms_b_txstatus(wlc->hw, bounded, &fatal)) ++ wlc->macintstatus |= MI_TFS; ++ if (fatal) { ++ wiphy_err(wiphy, "MI_TFS: fatal\n"); ++ goto fatal; ++ } ++ } ++ ++ if (macintstatus & (MI_TBTT | MI_DTIM_TBTT)) ++ brcms_c_tbtt(wlc); ++ ++ /* ATIM window end */ ++ if (macintstatus & MI_ATIMWINEND) { ++ BCMMSG(wlc->wiphy, "end of ATIM window\n"); ++ OR_REG(®s->maccommand, wlc->qvalid); ++ wlc->qvalid = 0; ++ } ++ ++ /* ++ * received data or control frame, MI_DMAINT is ++ * indication of RX_FIFO interrupt ++ */ ++ if (macintstatus & MI_DMAINT) ++ if (brcms_b_recv(wlc_hw, RX_FIFO, bounded)) ++ wlc->macintstatus |= MI_DMAINT; ++ ++ /* noise sample collected */ ++ if (macintstatus & MI_BG_NOISE) ++ wlc_phy_noise_sample_intr(wlc_hw->band->pi); ++ ++ if (macintstatus & MI_GP0) { ++ wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d " ++ "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); ++ ++ printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", ++ __func__, wlc_hw->sih->chip, ++ wlc_hw->sih->chiprev); ++ /* big hammer */ ++ brcms_init(wlc->wl); ++ } ++ ++ /* gptimer timeout */ ++ if (macintstatus & MI_TO) ++ W_REG(®s->gptimer, 0); ++ ++ if (macintstatus & MI_RFDISABLE) { ++ BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the" ++ " RF Disable Input\n", wlc_hw->unit); ++ brcms_rfkill_set_hw_state(wlc->wl); ++ } ++ ++ /* send any enq'd tx packets. Just makes sure to jump start tx */ ++ if (!pktq_empty(&wlc->pkt_queue->q)) ++ brcms_c_send_q(wlc); ++ ++ /* it isn't done and needs to be resched if macintstatus is non-zero */ ++ return wlc->macintstatus != 0; ++ ++ fatal: ++ brcms_init(wlc->wl); ++ return wlc->macintstatus != 0; ++} ++ ++void brcms_c_init(struct brcms_c_info *wlc) ++{ ++ struct d11regs __iomem *regs; ++ u16 chanspec; ++ bool mute = false; ++ ++ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); ++ ++ regs = wlc->regs; ++ ++ /* ++ * This will happen if a big-hammer was executed. In ++ * that case, we want to go back to the channel that ++ * we were on and not new channel ++ */ ++ if (wlc->pub->associated) ++ chanspec = wlc->home_chanspec; ++ else ++ chanspec = brcms_c_init_chanspec(wlc); ++ ++ brcms_b_init(wlc->hw, chanspec, mute); ++ ++ /* update beacon listen interval */ ++ brcms_c_bcn_li_upd(wlc); ++ ++ /* write ethernet address to core */ ++ brcms_c_set_mac(wlc->bsscfg); ++ brcms_c_set_bssid(wlc->bsscfg); ++ ++ /* Update tsf_cfprep if associated and up */ ++ if (wlc->pub->associated && wlc->bsscfg->up) { ++ u32 bi; ++ ++ /* get beacon period and convert to uS */ ++ bi = wlc->bsscfg->current_bss->beacon_period << 10; ++ /* ++ * update since init path would reset ++ * to default value ++ */ ++ W_REG(®s->tsf_cfprep, ++ (bi << CFPREP_CBI_SHIFT)); ++ ++ /* Update maccontrol PM related bits */ ++ brcms_c_set_ps_ctrl(wlc); ++ } ++ ++ brcms_c_bandinit_ordered(wlc, chanspec); ++ ++ /* init probe response timeout */ ++ brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout); ++ ++ /* init max burst txop (framebursting) */ ++ brcms_b_write_shm(wlc->hw, M_MBURST_TXOP, ++ (wlc-> ++ _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP)); ++ ++ /* initialize maximum allowed duty cycle */ ++ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true); ++ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true); ++ ++ /* ++ * Update some shared memory locations related to ++ * max AMPDU size allowed to received ++ */ ++ brcms_c_ampdu_shm_upd(wlc->ampdu); ++ ++ /* band-specific inits */ ++ brcms_c_bsinit(wlc); ++ ++ /* Enable EDCF mode (while the MAC is suspended) */ ++ OR_REG(®s->ifs_ctl, IFS_USEEDCF); ++ brcms_c_edcf_setparams(wlc, false); ++ ++ /* Init precedence maps for empty FIFOs */ ++ brcms_c_tx_prec_map_init(wlc); ++ ++ /* read the ucode version if we have not yet done so */ ++ if (wlc->ucode_rev == 0) { ++ wlc->ucode_rev = ++ brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16); ++ wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR); ++ } ++ ++ /* ..now really unleash hell (allow the MAC out of suspend) */ ++ brcms_c_enable_mac(wlc); ++ ++ /* clear tx flow control */ ++ brcms_c_txflowcontrol_reset(wlc); ++ ++ /* enable the RF Disable Delay timer */ ++ W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT); ++ ++ /* initialize mpc delay */ ++ wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; ++ ++ /* ++ * Initialize WME parameters; if they haven't been set by some other ++ * mechanism (IOVar, etc) then read them from the hardware. ++ */ ++ if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) { ++ /* Uninitialized; read from HW */ ++ int ac; ++ ++ for (ac = 0; ac < AC_COUNT; ac++) ++ wlc->wme_retries[ac] = ++ brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac)); ++ } ++} ++ ++/* ++ * The common driver entry routine. Error codes should be unique ++ */ ++struct brcms_c_info * ++brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, ++ bool piomode, void __iomem *regsva, struct pci_dev *btparam, ++ uint *perr) ++{ ++ struct brcms_c_info *wlc; ++ uint err = 0; ++ uint i, j; ++ struct brcms_pub *pub; ++ ++ /* allocate struct brcms_c_info state and its substructures */ ++ wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device); ++ if (wlc == NULL) ++ goto fail; ++ wlc->wiphy = wl->wiphy; ++ pub = wlc->pub; ++ ++#if defined(BCMDBG) ++ wlc_info_dbg = wlc; ++#endif ++ ++ wlc->band = wlc->bandstate[0]; ++ wlc->core = wlc->corestate; ++ wlc->wl = wl; ++ pub->unit = unit; ++ pub->_piomode = piomode; ++ wlc->bandinit_pending = false; ++ ++ /* populate struct brcms_c_info with default values */ ++ brcms_c_info_init(wlc, unit); ++ ++ /* update sta/ap related parameters */ ++ brcms_c_ap_upd(wlc); ++ ++ /* ++ * low level attach steps(all hw accesses go ++ * inside, no more in rest of the attach) ++ */ ++ err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva, ++ btparam); ++ if (err) ++ goto fail; ++ ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF); ++ ++ pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band); ++ ++ /* disable allowed duty cycle */ ++ wlc->tx_duty_cycle_ofdm = 0; ++ wlc->tx_duty_cycle_cck = 0; ++ ++ brcms_c_stf_phy_chain_calc(wlc); ++ ++ /* txchain 1: txant 0, txchain 2: txant 1 */ ++ if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1)) ++ wlc->stf->txant = wlc->stf->hw_txchain - 1; ++ ++ /* push to BMAC driver */ ++ wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain, ++ wlc->stf->hw_rxchain); ++ ++ /* pull up some info resulting from the low attach */ ++ for (i = 0; i < NFIFO; i++) ++ wlc->core->txavail[i] = wlc->hw->txavail[i]; ++ ++ memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN); ++ memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN); ++ ++ for (j = 0; j < wlc->pub->_nbands; j++) { ++ wlc->band = wlc->bandstate[j]; ++ ++ if (!brcms_c_attach_stf_ant_init(wlc)) { ++ err = 24; ++ goto fail; ++ } ++ ++ /* default contention windows size limits */ ++ wlc->band->CWmin = APHY_CWMIN; ++ wlc->band->CWmax = PHY_CWMAX; ++ ++ /* init gmode value */ ++ if (wlc->band->bandtype == BRCM_BAND_2G) { ++ wlc->band->gmode = GMODE_AUTO; ++ brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, ++ wlc->band->gmode); ++ } ++ ++ /* init _n_enab supported mode */ ++ if (BRCMS_PHY_11N_CAP(wlc->band)) { ++ pub->_n_enab = SUPPORT_11N; ++ brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER, ++ ((pub->_n_enab == ++ SUPPORT_11N) ? WL_11N_2x2 : ++ WL_11N_3x3)); ++ } ++ ++ /* init per-band default rateset, depend on band->gmode */ ++ brcms_default_rateset(wlc, &wlc->band->defrateset); ++ ++ /* fill in hw_rateset */ ++ brcms_c_rateset_filter(&wlc->band->defrateset, ++ &wlc->band->hw_rateset, false, ++ BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, ++ (bool) (wlc->pub->_n_enab & SUPPORT_11N)); ++ } ++ ++ /* ++ * update antenna config due to ++ * wlc->stf->txant/txchain/ant_rx_ovr change ++ */ ++ brcms_c_stf_phy_txant_upd(wlc); ++ ++ /* attach each modules */ ++ err = brcms_c_attach_module(wlc); ++ if (err != 0) ++ goto fail; ++ ++ if (!brcms_c_timers_init(wlc, unit)) { ++ wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit, ++ __func__); ++ err = 32; ++ goto fail; ++ } ++ ++ /* depend on rateset, gmode */ ++ wlc->cmi = brcms_c_channel_mgr_attach(wlc); ++ if (!wlc->cmi) { ++ wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed" ++ "\n", unit, __func__); ++ err = 33; ++ goto fail; ++ } ++ ++ /* init default when all parameters are ready, i.e. ->rateset */ ++ brcms_c_bss_default_init(wlc); ++ ++ /* ++ * Complete the wlc default state initializations.. ++ */ ++ ++ /* allocate our initial queue */ ++ wlc->pkt_queue = brcms_c_txq_alloc(wlc); ++ if (wlc->pkt_queue == NULL) { ++ wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n", ++ unit, __func__); ++ err = 100; ++ goto fail; ++ } ++ ++ wlc->bsscfg->wlc = wlc; ++ ++ wlc->mimoft = FT_HT; ++ wlc->mimo_40txbw = AUTO; ++ wlc->ofdm_40txbw = AUTO; ++ wlc->cck_40txbw = AUTO; ++ brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G); ++ ++ /* Set default values of SGI */ ++ if (BRCMS_SGI_CAP_PHY(wlc)) { ++ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | ++ BRCMS_N_SGI_40)); ++ } else if (BRCMS_ISSSLPNPHY(wlc->band)) { ++ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | ++ BRCMS_N_SGI_40)); ++ } else { ++ brcms_c_ht_update_sgi_rx(wlc, 0); ++ } ++ ++ /* initialize radio_mpc_disable according to wlc->mpc */ ++ brcms_c_radio_mpc_upd(wlc); ++ brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail); ++ ++ if (perr) ++ *perr = 0; ++ ++ return wlc; ++ ++ fail: ++ wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n", ++ unit, __func__, err); ++ if (wlc) ++ brcms_c_detach(wlc); ++ ++ if (perr) ++ *perr = err; ++ return NULL; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.h.orig 2011-11-09 13:46:58.251800557 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/main.h 2011-11-09 13:47:17.004566116 -0500 +@@ -0,0 +1,735 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_MAIN_H_ ++#define _BRCM_MAIN_H_ ++ ++#include ++ ++#include ++#include "types.h" ++#include "d11.h" ++#include "scb.h" ++ ++#define INVCHANNEL 255 /* invalid channel */ ++ ++/* max # brcms_c_module_register() calls */ ++#define BRCMS_MAXMODULES 22 ++ ++#define SEQNUM_SHIFT 4 ++#define SEQNUM_MAX 0x1000 ++ ++#define NTXRATE 64 /* # tx MPDUs rate is reported for */ ++ ++/* Maximum wait time for a MAC suspend */ ++/* uS: 83mS is max packet time (64KB ampdu @ 6Mbps) */ ++#define BRCMS_MAX_MAC_SUSPEND 83000 ++ ++/* responses for probe requests older that this are tossed, zero to disable */ ++#define BRCMS_PRB_RESP_TIMEOUT 0 /* Disable probe response timeout */ ++ ++/* transmit buffer max headroom for protocol headers */ ++#define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN) ++ ++#define AC_COUNT 4 ++ ++/* Macros for doing definition and get/set of bitfields ++ * Usage example, e.g. a three-bit field (bits 4-6): ++ * #define _M BITFIELD_MASK(3) ++ * #define _S 4 ++ * ... ++ * regval = R_REG(osh, ®s->regfoo); ++ * field = GFIELD(regval, ); ++ * regval = SFIELD(regval, , 1); ++ * W_REG(osh, ®s->regfoo, regval); ++ */ ++#define BITFIELD_MASK(width) \ ++ (((unsigned)1 << (width)) - 1) ++#define GFIELD(val, field) \ ++ (((val) >> field ## _S) & field ## _M) ++#define SFIELD(val, field, bits) \ ++ (((val) & (~(field ## _M << field ## _S))) | \ ++ ((unsigned)(bits) << field ## _S)) ++ ++#define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */ ++ ++/* max # supported core revisions (0 .. MAXCOREREV - 1) */ ++#define MAXCOREREV 28 ++ ++/* Double check that unsupported cores are not enabled */ ++#if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV) ++#error "Configuration for D11CONF includes unsupported versions." ++#endif /* Bad versions */ ++ ++/* values for shortslot_override */ ++#define BRCMS_SHORTSLOT_AUTO -1 /* Driver will manage Shortslot setting */ ++#define BRCMS_SHORTSLOT_OFF 0 /* Turn off short slot */ ++#define BRCMS_SHORTSLOT_ON 1 /* Turn on short slot */ ++ ++/* value for short/long and mixmode/greenfield preamble */ ++#define BRCMS_LONG_PREAMBLE (0) ++#define BRCMS_SHORT_PREAMBLE (1 << 0) ++#define BRCMS_GF_PREAMBLE (1 << 1) ++#define BRCMS_MM_PREAMBLE (1 << 2) ++#define BRCMS_IS_MIMO_PREAMBLE(_pre) (((_pre) == BRCMS_GF_PREAMBLE) || \ ++ ((_pre) == BRCMS_MM_PREAMBLE)) ++ ++/* TxFrameID */ ++/* seq and frag bits: SEQNUM_SHIFT, FRAGNUM_MASK (802.11.h) */ ++/* rate epoch bits: TXFID_RATE_SHIFT, TXFID_RATE_MASK ((wlc_rate.c) */ ++#define TXFID_QUEUE_MASK 0x0007 /* Bits 0-2 */ ++#define TXFID_SEQ_MASK 0x7FE0 /* Bits 5-15 */ ++#define TXFID_SEQ_SHIFT 5 /* Number of bit shifts */ ++#define TXFID_RATE_PROBE_MASK 0x8000 /* Bit 15 for rate probe */ ++#define TXFID_RATE_MASK 0x0018 /* Mask for bits 3 and 4 */ ++#define TXFID_RATE_SHIFT 3 /* Shift 3 bits for rate mask */ ++ ++/* promote boardrev */ ++#define BOARDREV_PROMOTABLE 0xFF /* from */ ++#define BOARDREV_PROMOTED 1 /* to */ ++ ++#define DATA_BLOCK_TX_SUPR (1 << 4) ++ ++/* 802.1D Priority to TX FIFO number for wme */ ++extern const u8 prio2fifo[]; ++ ++/* Ucode MCTL_WAKE override bits */ ++#define BRCMS_WAKE_OVERRIDE_CLKCTL 0x01 ++#define BRCMS_WAKE_OVERRIDE_PHYREG 0x02 ++#define BRCMS_WAKE_OVERRIDE_MACSUSPEND 0x04 ++#define BRCMS_WAKE_OVERRIDE_TXFIFO 0x08 ++#define BRCMS_WAKE_OVERRIDE_FORCEFAST 0x10 ++ ++/* stuff pulled in from wlc.c */ ++ ++/* Interrupt bit error summary. Don't include I_RU: we refill DMA at other ++ * times; and if we run out, constant I_RU interrupts may cause lockup. We ++ * will still get error counts from rx0ovfl. ++ */ ++#define I_ERRORS (I_PC | I_PD | I_DE | I_RO | I_XU) ++/* default software intmasks */ ++#define DEF_RXINTMASK (I_RI) /* enable rx int on rxfifo only */ ++#define DEF_MACINTMASK (MI_TXSTOP | MI_TBTT | MI_ATIMWINEND | MI_PMQ | \ ++ MI_PHYTXERR | MI_DMAINT | MI_TFS | MI_BG_NOISE | \ ++ MI_CCA | MI_TO | MI_GP0 | MI_RFDISABLE | MI_PWRUP) ++ ++#define MAXTXPKTS 6 /* max # pkts pending */ ++ ++/* frameburst */ ++#define MAXTXFRAMEBURST 8 /* vanilla xpress mode: max frames/burst */ ++#define MAXFRAMEBURST_TXOP 10000 /* Frameburst TXOP in usec */ ++ ++#define NFIFO 6 /* # tx/rx fifopairs */ ++ ++/* PLL requests */ ++ ++/* pll is shared on old chips */ ++#define BRCMS_PLLREQ_SHARED 0x1 ++/* hold pll for radio monitor register checking */ ++#define BRCMS_PLLREQ_RADIO_MON 0x2 ++/* hold/release pll for some short operation */ ++#define BRCMS_PLLREQ_FLIP 0x4 ++ ++#define CHANNEL_BANDUNIT(wlc, ch) \ ++ (((ch) <= CH_MAX_2G_CHANNEL) ? BAND_2G_INDEX : BAND_5G_INDEX) ++ ++#define OTHERBANDUNIT(wlc) \ ++ ((uint)((wlc)->band->bandunit ? BAND_2G_INDEX : BAND_5G_INDEX)) ++ ++/* ++ * 802.11 protection information ++ * ++ * _g: use g spec protection, driver internal. ++ * g_override: override for use of g spec protection. ++ * gmode_user: user config gmode, operating band->gmode is different. ++ * overlap: Overlap BSS/IBSS protection for both 11g and 11n. ++ * nmode_user: user config nmode, operating pub->nmode is different. ++ * n_cfg: use OFDM protection on MIMO frames. ++ * n_cfg_override: override for use of N protection. ++ * nongf: non-GF present protection. ++ * nongf_override: override for use of GF protection. ++ * n_pam_override: override for preamble: MM or GF. ++ * n_obss: indicated OBSS Non-HT STA present. ++*/ ++struct brcms_protection { ++ bool _g; ++ s8 g_override; ++ u8 gmode_user; ++ s8 overlap; ++ s8 nmode_user; ++ s8 n_cfg; ++ s8 n_cfg_override; ++ bool nongf; ++ s8 nongf_override; ++ s8 n_pam_override; ++ bool n_obss; ++}; ++ ++/* ++ * anything affecting the single/dual streams/antenna operation ++ * ++ * hw_txchain: HW txchain bitmap cfg. ++ * txchain: txchain bitmap being used. ++ * txstreams: number of txchains being used. ++ * hw_rxchain: HW rxchain bitmap cfg. ++ * rxchain: rxchain bitmap being used. ++ * rxstreams: number of rxchains being used. ++ * ant_rx_ovr: rx antenna override. ++ * txant: userTx antenna setting. ++ * phytxant: phyTx antenna setting in txheader. ++ * ss_opmode: singlestream Operational mode, 0:siso; 1:cdd. ++ * ss_algosel_auto: if true, use wlc->stf->ss_algo_channel; ++ * else use wlc->band->stf->ss_mode_band. ++ * ss_algo_channel: ss based on per-channel algo: 0: SISO, 1: CDD 2: STBC. ++ * rxchain_restore_delay: delay time to restore default rxchain. ++ * ldpc: AUTO/ON/OFF ldpc cap supported. ++ * txcore[MAX_STREAMS_SUPPORTED + 1]: bitmap of selected core for each Nsts. ++ * spatial_policy: ++ */ ++struct brcms_stf { ++ u8 hw_txchain; ++ u8 txchain; ++ u8 txstreams; ++ u8 hw_rxchain; ++ u8 rxchain; ++ u8 rxstreams; ++ u8 ant_rx_ovr; ++ s8 txant; ++ u16 phytxant; ++ u8 ss_opmode; ++ bool ss_algosel_auto; ++ u16 ss_algo_channel; ++ u8 rxchain_restore_delay; ++ s8 ldpc; ++ u8 txcore[MAX_STREAMS_SUPPORTED + 1]; ++ s8 spatial_policy; ++}; ++ ++#define BRCMS_STF_SS_STBC_TX(wlc, scb) \ ++ (((wlc)->stf->txstreams > 1) && (((wlc)->band->band_stf_stbc_tx == ON) \ ++ || (((scb)->flags & SCB_STBCCAP) && \ ++ (wlc)->band->band_stf_stbc_tx == AUTO && \ ++ isset(&((wlc)->stf->ss_algo_channel), PHY_TXC1_MODE_STBC)))) ++ ++#define BRCMS_STBC_CAP_PHY(wlc) (BRCMS_ISNPHY(wlc->band) && \ ++ NREV_GE(wlc->band->phyrev, 3)) ++ ++#define BRCMS_SGI_CAP_PHY(wlc) ((BRCMS_ISNPHY(wlc->band) && \ ++ NREV_GE(wlc->band->phyrev, 3)) || \ ++ BRCMS_ISLCNPHY(wlc->band)) ++ ++#define BRCMS_CHAN_PHYTYPE(x) (((x) & RXS_CHAN_PHYTYPE_MASK) \ ++ >> RXS_CHAN_PHYTYPE_SHIFT) ++#define BRCMS_CHAN_CHANNEL(x) (((x) & RXS_CHAN_ID_MASK) \ ++ >> RXS_CHAN_ID_SHIFT) ++ ++/* ++ * core state (mac) ++ */ ++struct brcms_core { ++ uint coreidx; /* # sb enumerated core */ ++ ++ /* fifo */ ++ uint *txavail[NFIFO]; /* # tx descriptors available */ ++ s16 txpktpend[NFIFO]; /* tx admission control */ ++ ++ struct macstat *macstat_snapshot; /* mac hw prev read values */ ++}; ++ ++/* ++ * band state (phy+ana+radio) ++ */ ++struct brcms_band { ++ int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */ ++ uint bandunit; /* bandstate[] index */ ++ ++ u16 phytype; /* phytype */ ++ u16 phyrev; ++ u16 radioid; ++ u16 radiorev; ++ struct brcms_phy_pub *pi; /* pointer to phy specific information */ ++ bool abgphy_encore; ++ ++ u8 gmode; /* currently active gmode */ ++ ++ struct scb *hwrs_scb; /* permanent scb for hw rateset */ ++ ++ /* band-specific copy of default_bss.rateset */ ++ struct brcms_c_rateset defrateset; ++ ++ u8 band_stf_ss_mode; /* Configured STF type, 0:siso; 1:cdd */ ++ s8 band_stf_stbc_tx; /* STBC TX 0:off; 1:force on; -1:auto */ ++ /* rates supported by chip (phy-specific) */ ++ struct brcms_c_rateset hw_rateset; ++ u8 basic_rate[BRCM_MAXRATE + 1]; /* basic rates indexed by rate */ ++ bool mimo_cap_40; /* 40 MHz cap enabled on this band */ ++ s8 antgain; /* antenna gain from srom */ ++ ++ u16 CWmin; /* minimum size of contention window, in unit of aSlotTime */ ++ u16 CWmax; /* maximum size of contention window, in unit of aSlotTime */ ++ struct ieee80211_supported_band band; ++}; ++ ++/* module control blocks */ ++struct modulecb { ++ /* module name : NULL indicates empty array member */ ++ char name[32]; ++ /* handle passed when handler 'doiovar' is called */ ++ struct brcms_info *hdl; ++ ++ int (*down_fn)(void *handle); /* down handler. Note: the int returned ++ * by the down function is a count of the ++ * number of timers that could not be ++ * freed. ++ */ ++ ++}; ++ ++struct brcms_hw_band { ++ int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */ ++ uint bandunit; /* bandstate[] index */ ++ u16 mhfs[MHFMAX]; /* MHF array shadow */ ++ u8 bandhw_stf_ss_mode; /* HW configured STF type, 0:siso; 1:cdd */ ++ u16 CWmin; ++ u16 CWmax; ++ u32 core_flags; ++ ++ u16 phytype; /* phytype */ ++ u16 phyrev; ++ u16 radioid; ++ u16 radiorev; ++ struct brcms_phy_pub *pi; /* pointer to phy specific information */ ++ bool abgphy_encore; ++}; ++ ++struct brcms_hardware { ++ bool _piomode; /* true if pio mode */ ++ struct brcms_c_info *wlc; ++ ++ /* fifo */ ++ struct dma_pub *di[NFIFO]; /* dma handles, per fifo */ ++ ++ uint unit; /* device instance number */ ++ ++ /* version info */ ++ u16 vendorid; /* PCI vendor id */ ++ u16 deviceid; /* PCI device id */ ++ uint corerev; /* core revision */ ++ u8 sromrev; /* version # of the srom */ ++ u16 boardrev; /* version # of particular board */ ++ u32 boardflags; /* Board specific flags from srom */ ++ u32 boardflags2; /* More board flags if sromrev >= 4 */ ++ u32 machwcap; /* MAC capabilities */ ++ u32 machwcap_backup; /* backup of machwcap */ ++ ++ struct si_pub *sih; /* SI handle (cookie for siutils calls) */ ++ struct d11regs __iomem *regs; /* pointer to device registers */ ++ struct phy_shim_info *physhim; /* phy shim layer handler */ ++ struct shared_phy *phy_sh; /* pointer to shared phy state */ ++ struct brcms_hw_band *band;/* pointer to active per-band state */ ++ /* band state per phy/radio */ ++ struct brcms_hw_band *bandstate[MAXBANDS]; ++ u16 bmac_phytxant; /* cache of high phytxant state */ ++ bool shortslot; /* currently using 11g ShortSlot timing */ ++ u16 SRL; /* 802.11 dot11ShortRetryLimit */ ++ u16 LRL; /* 802.11 dot11LongRetryLimit */ ++ u16 SFBL; /* Short Frame Rate Fallback Limit */ ++ u16 LFBL; /* Long Frame Rate Fallback Limit */ ++ ++ bool up; /* d11 hardware up and running */ ++ uint now; /* # elapsed seconds */ ++ uint _nbands; /* # bands supported */ ++ u16 chanspec; /* bmac chanspec shadow */ ++ ++ uint *txavail[NFIFO]; /* # tx descriptors available */ ++ const u16 *xmtfifo_sz; /* fifo size in 256B for each xmt fifo */ ++ ++ u32 pllreq; /* pll requests to keep PLL on */ ++ ++ u8 suspended_fifos; /* Which TX fifo to remain awake for */ ++ u32 maccontrol; /* Cached value of maccontrol */ ++ uint mac_suspend_depth; /* current depth of mac_suspend levels */ ++ u32 wake_override; /* bit flags to force MAC to WAKE mode */ ++ u32 mute_override; /* Prevent ucode from sending beacons */ ++ u8 etheraddr[ETH_ALEN]; /* currently configured ethernet address */ ++ bool noreset; /* true= do not reset hw, used by WLC_OUT */ ++ bool forcefastclk; /* true if h/w is forcing to use fast clk */ ++ bool clk; /* core is out of reset and has clock */ ++ bool sbclk; /* sb has clock */ ++ bool phyclk; /* phy is out of reset and has clock */ ++ ++ bool ucode_loaded; /* true after ucode downloaded */ ++ ++ ++ u8 hw_stf_ss_opmode; /* STF single stream operation mode */ ++ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic ++ * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board ++ */ ++ u32 antsel_avail; /* ++ * put struct antsel_info here if more info is ++ * needed ++ */ ++}; ++ ++/* TX Queue information ++ * ++ * Each flow of traffic out of the device has a TX Queue with independent ++ * flow control. Several interfaces may be associated with a single TX Queue ++ * if they belong to the same flow of traffic from the device. For multi-channel ++ * operation there are independent TX Queues for each channel. ++ */ ++struct brcms_txq_info { ++ struct brcms_txq_info *next; ++ struct pktq q; ++ uint stopped; /* tx flow control bits */ ++}; ++ ++/* ++ * Principal common driver data structure. ++ * ++ * pub: pointer to driver public state. ++ * wl: pointer to specific private state. ++ * regs: pointer to device registers. ++ * hw: HW related state. ++ * clkreq_override: setting for clkreq for PCIE : Auto, 0, 1. ++ * fastpwrup_dly: time in us needed to bring up d11 fast clock. ++ * macintstatus: bit channel between isr and dpc. ++ * macintmask: sw runtime master macintmask value. ++ * defmacintmask: default "on" macintmask value. ++ * clk: core is out of reset and has clock. ++ * core: pointer to active io core. ++ * band: pointer to active per-band state. ++ * corestate: per-core state (one per hw core). ++ * bandstate: per-band state (one per phy/radio). ++ * qvalid: DirFrmQValid and BcMcFrmQValid. ++ * ampdu: ampdu module handler. ++ * asi: antsel module handler. ++ * cmi: channel manager module handler. ++ * vendorid: PCI vendor id. ++ * deviceid: PCI device id. ++ * ucode_rev: microcode revision. ++ * machwcap: MAC capabilities, BMAC shadow. ++ * perm_etheraddr: original sprom local ethernet address. ++ * bandlocked: disable auto multi-band switching. ++ * bandinit_pending: track band init in auto band. ++ * radio_monitor: radio timer is running. ++ * going_down: down path intermediate variable. ++ * mpc: enable minimum power consumption. ++ * mpc_dlycnt: # of watchdog cnt before turn disable radio. ++ * mpc_offcnt: # of watchdog cnt that radio is disabled. ++ * mpc_delay_off: delay radio disable by # of watchdog cnt. ++ * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc. ++ * wdtimer: timer for watchdog routine. ++ * radio_timer: timer for hw radio button monitor routine. ++ * monitor: monitor (MPDU sniffing) mode. ++ * bcnmisc_monitor: bcns promisc mode override for monitor. ++ * _rifs: enable per-packet rifs. ++ * bcn_li_bcn: beacon listen interval in # beacons. ++ * bcn_li_dtim: beacon listen interval in # dtims. ++ * WDarmed: watchdog timer is armed. ++ * WDlast: last time wlc_watchdog() was called. ++ * edcf_txop[AC_COUNT]: current txop for each ac. ++ * wme_retries: per-AC retry limits. ++ * tx_prec_map: Precedence map based on HW FIFO space. ++ * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME. ++ * bsscfg: set of BSS configurations, idx 0 is default and always valid. ++ * cfg: the primary bsscfg (can be AP or STA). ++ * tx_queues: common TX Queue list. ++ * modulecb: ++ * mimoft: SIGN or 11N. ++ * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode. ++ * ofdm_40txbw: 11N, ofdm tx b/w override when in 40MHZ mode. ++ * mimo_40txbw: 11N, mimo tx b/w override when in 40MHZ mode. ++ * default_bss: configured BSS parameters. ++ * mc_fid_counter: BC/MC FIFO frame ID counter. ++ * country_default: saved country for leaving 802.11d auto-country mode. ++ * autocountry_default: initial country for 802.11d auto-country mode. ++ * prb_resp_timeout: do not send prb resp if request older ++ * than this, 0 = disable. ++ * home_chanspec: shared home chanspec. ++ * chanspec: target operational channel. ++ * usr_fragthresh: user configured fragmentation threshold. ++ * fragthresh[NFIFO]: per-fifo fragmentation thresholds. ++ * RTSThresh: 802.11 dot11RTSThreshold. ++ * SRL: 802.11 dot11ShortRetryLimit. ++ * LRL: 802.11 dot11LongRetryLimit. ++ * SFBL: Short Frame Rate Fallback Limit. ++ * LFBL: Long Frame Rate Fallback Limit. ++ * shortslot: currently using 11g ShortSlot timing. ++ * shortslot_override: 11g ShortSlot override. ++ * include_legacy_erp: include Legacy ERP info elt ID 47 as well as g ID 42. ++ * PLCPHdr_override: 802.11b Preamble Type override. ++ * stf: ++ * bcn_rspec: save bcn ratespec purpose. ++ * tempsense_lasttime; ++ * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM. ++ * tx_duty_cycle_cck: maximum allowed duty cycle for CCK. ++ * pkt_queue: txq for transmit packets. ++ * wiphy: ++ * pri_scb: primary Station Control Block ++ */ ++struct brcms_c_info { ++ struct brcms_pub *pub; ++ struct brcms_info *wl; ++ struct d11regs __iomem *regs; ++ struct brcms_hardware *hw; ++ ++ /* clock */ ++ u16 fastpwrup_dly; ++ ++ /* interrupt */ ++ u32 macintstatus; ++ u32 macintmask; ++ u32 defmacintmask; ++ ++ bool clk; ++ ++ /* multiband */ ++ struct brcms_core *core; ++ struct brcms_band *band; ++ struct brcms_core *corestate; ++ struct brcms_band *bandstate[MAXBANDS]; ++ ++ /* packet queue */ ++ uint qvalid; ++ ++ struct ampdu_info *ampdu; ++ struct antsel_info *asi; ++ struct brcms_cm_info *cmi; ++ ++ u16 vendorid; ++ u16 deviceid; ++ uint ucode_rev; ++ ++ u8 perm_etheraddr[ETH_ALEN]; ++ ++ bool bandlocked; ++ bool bandinit_pending; ++ ++ bool radio_monitor; ++ bool going_down; ++ ++ bool mpc; ++ u8 mpc_dlycnt; ++ u8 mpc_offcnt; ++ u8 mpc_delay_off; ++ u8 prev_non_delay_mpc; ++ ++ struct brcms_timer *wdtimer; ++ struct brcms_timer *radio_timer; ++ ++ /* promiscuous */ ++ bool monitor; ++ bool bcnmisc_monitor; ++ ++ /* driver feature */ ++ bool _rifs; ++ ++ /* AP-STA synchronization, power save */ ++ u8 bcn_li_bcn; ++ u8 bcn_li_dtim; ++ ++ bool WDarmed; ++ u32 WDlast; ++ ++ /* WME */ ++ u16 edcf_txop[AC_COUNT]; ++ ++ u16 wme_retries[AC_COUNT]; ++ u16 tx_prec_map; ++ u16 fifo2prec_map[NFIFO]; ++ ++ struct brcms_bss_cfg *bsscfg; ++ ++ /* tx queue */ ++ struct brcms_txq_info *tx_queues; ++ ++ struct modulecb *modulecb; ++ ++ u8 mimoft; ++ s8 cck_40txbw; ++ s8 ofdm_40txbw; ++ s8 mimo_40txbw; ++ ++ struct brcms_bss_info *default_bss; ++ ++ u16 mc_fid_counter; ++ ++ char country_default[BRCM_CNTRY_BUF_SZ]; ++ char autocountry_default[BRCM_CNTRY_BUF_SZ]; ++ u16 prb_resp_timeout; ++ ++ u16 home_chanspec; ++ ++ /* PHY parameters */ ++ u16 chanspec; ++ u16 usr_fragthresh; ++ u16 fragthresh[NFIFO]; ++ u16 RTSThresh; ++ u16 SRL; ++ u16 LRL; ++ u16 SFBL; ++ u16 LFBL; ++ ++ /* network config */ ++ bool shortslot; ++ s8 shortslot_override; ++ bool include_legacy_erp; ++ ++ struct brcms_protection *protection; ++ s8 PLCPHdr_override; ++ ++ struct brcms_stf *stf; ++ ++ u32 bcn_rspec; ++ ++ uint tempsense_lasttime; ++ ++ u16 tx_duty_cycle_ofdm; ++ u16 tx_duty_cycle_cck; ++ ++ struct brcms_txq_info *pkt_queue; ++ struct wiphy *wiphy; ++ struct scb pri_scb; ++}; ++ ++/* antsel module specific state */ ++struct antsel_info { ++ struct brcms_c_info *wlc; /* pointer to main wlc structure */ ++ struct brcms_pub *pub; /* pointer to public fn */ ++ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic ++ * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board ++ */ ++ u8 antsel_antswitch; /* board level antenna switch type */ ++ bool antsel_avail; /* Ant selection availability (SROM based) */ ++ struct brcms_antselcfg antcfg_11n; /* antenna configuration */ ++ struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */ ++}; ++ ++/* ++ * BSS configuration state ++ * ++ * wlc: wlc to which this bsscfg belongs to. ++ * up: is this configuration up operational ++ * enable: is this configuration enabled ++ * associated: is BSS in ASSOCIATED state ++ * BSS: infraustructure or adhoc ++ * SSID_len: the length of SSID ++ * SSID: SSID string ++ * ++ * ++ * BSSID: BSSID (associated) ++ * cur_etheraddr: h/w address ++ * flags: BSSCFG flags; see below ++ * ++ * current_bss: BSS parms in ASSOCIATED state ++ * ++ * ++ * ID: 'unique' ID of this bsscfg, assigned at bsscfg allocation ++ */ ++struct brcms_bss_cfg { ++ struct brcms_c_info *wlc; ++ bool up; ++ bool enable; ++ bool associated; ++ bool BSS; ++ u8 SSID_len; ++ u8 SSID[IEEE80211_MAX_SSID_LEN]; ++ u8 BSSID[ETH_ALEN]; ++ u8 cur_etheraddr[ETH_ALEN]; ++ struct brcms_bss_info *current_bss; ++}; ++ ++extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, ++ struct sk_buff *p, ++ bool commit, s8 txpktpend); ++extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, ++ s8 txpktpend); ++extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, ++ struct sk_buff *sdu, uint prec); ++extern void brcms_c_print_txstatus(struct tx_status *txs); ++extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, ++ uint *blocks); ++ ++#if defined(BCMDBG) ++extern void brcms_c_print_txdesc(struct d11txh *txh); ++#else ++#define brcms_c_print_txdesc(a) ++#endif ++ ++extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); ++extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, ++ bool promisc); ++extern void brcms_c_send_q(struct brcms_c_info *wlc); ++extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, ++ uint *fifo); ++extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, ++ uint mac_len); ++extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, ++ u32 rspec, ++ bool use_rspec, u16 mimo_ctlchbw); ++extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, ++ u32 rts_rate, ++ u32 frame_rate, ++ u8 rts_preamble_type, ++ u8 frame_preamble_type, uint frame_len, ++ bool ba); ++extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, ++ struct ieee80211_sta *sta, ++ void (*dma_callback_fn)); ++extern void brcms_c_update_beacon(struct brcms_c_info *wlc); ++extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); ++extern int brcms_c_set_nmode(struct brcms_c_info *wlc); ++extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, ++ u32 bcn_rate); ++extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, ++ u8 antsel_type); ++extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, ++ u16 chanspec, ++ bool mute, struct txpwr_limits *txpwr); ++extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, ++ u16 v); ++extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset); ++extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, ++ u16 val, int bands); ++extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags); ++extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val); ++extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw); ++extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw); ++extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw); ++extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, ++ u32 override_bit); ++extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, ++ u32 override_bit); ++extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, ++ int offset, int len, void *buf); ++extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate); ++extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, ++ uint offset, const void *buf, int len, ++ u32 sel); ++extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, ++ void *buf, int len, u32 sel); ++extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode); ++extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw); ++extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk); ++extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk); ++extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on); ++extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant); ++extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, ++ u8 stf_mode); ++extern void brcms_c_init_scb(struct scb *scb); ++ ++#endif /* _BRCM_MAIN_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/Makefile.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/Makefile +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/Makefile.orig 2011-11-09 13:46:58.251800557 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/Makefile 2011-11-09 13:47:17.005566104 -0500 +@@ -0,0 +1,51 @@ ++# ++# Makefile fragment for Broadcom 802.11n Networking Device Driver ++# ++# Copyright (c) 2010 Broadcom Corporation ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# 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. ++ ++ccflags-y := \ ++ -D__CHECK_ENDIAN__ \ ++ -Idrivers/net/wireless/brcm80211/brcmsmac \ ++ -Idrivers/net/wireless/brcm80211/brcmsmac/phy \ ++ -Idrivers/net/wireless/brcm80211/include ++ ++BRCMSMAC_OFILES := \ ++ mac80211_if.o \ ++ ucode_loader.o \ ++ ampdu.o \ ++ antsel.o \ ++ channel.o \ ++ main.o \ ++ phy_shim.o \ ++ pmu.o \ ++ rate.o \ ++ stf.o \ ++ aiutils.o \ ++ phy/phy_cmn.o \ ++ phy/phy_lcn.o \ ++ phy/phy_n.o \ ++ phy/phytbl_lcn.o \ ++ phy/phytbl_n.o \ ++ phy/phy_qmath.o \ ++ otp.o \ ++ srom.o \ ++ dma.o \ ++ nicpci.o \ ++ brcms_trace_events.o ++ ++MODULEPFX := brcmsmac ++ ++obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o ++$(MODULEPFX)-objs = $(BRCMSMAC_OFILES) +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c.orig 2011-11-09 13:46:58.252800545 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c 2011-11-09 13:47:17.005566104 -0500 +@@ -0,0 +1,835 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include "aiutils.h" ++#include "pub.h" ++#include "nicpci.h" ++ ++/* SPROM offsets */ ++#define SRSH_ASPM_OFFSET 4 /* word 4 */ ++#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */ ++#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */ ++#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */ ++ ++#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */ ++#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ ++#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ ++#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ ++#define SRSH_BD_OFFSET 6 /* word 6 */ ++ ++/* chipcontrol */ ++#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */ ++ ++/* MDIO control */ ++#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ ++#define MDIOCTL_DIVISOR_VAL 0x2 ++#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */ ++#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */ ++ ++/* MDIO Data */ ++#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ ++#define MDIODATA_TA 0x00020000 /* Turnaround */ ++ ++#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */ ++#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */ ++#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */ ++#define MDIODATA_DEVADDR_MASK 0x0f800000 ++ /* Physmedia devaddr Mask */ ++ ++/* MDIO Data for older revisions < 10 */ ++#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */ ++#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 ++ /* Regaddr Mask */ ++#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */ ++#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 ++ /* Physmedia devaddr Mask */ ++ ++/* Transactions flags */ ++#define MDIODATA_WRITE 0x10000000 ++#define MDIODATA_READ 0x20000000 ++#define MDIODATA_START 0x40000000 ++ ++#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ ++#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ ++ ++/* serdes regs (rev < 10) */ ++#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */ ++#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */ ++#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */ ++ ++/* SERDES RX registers */ ++#define SERDES_RX_CTRL 1 /* Rx cntrl */ ++#define SERDES_RX_TIMER1 2 /* Rx Timer1 */ ++#define SERDES_RX_CDR 6 /* CDR */ ++#define SERDES_RX_CDRBW 7 /* CDR BW */ ++/* SERDES RX control register */ ++#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */ ++#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */ ++ ++/* SERDES PLL registers */ ++#define SERDES_PLL_CTRL 1 /* PLL control reg */ ++#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */ ++ ++/* Linkcontrol reg offset in PCIE Cap */ ++#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */ ++#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */ ++#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */ ++#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */ ++ ++#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */ ++ ++/* Power management threshold */ ++#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */ ++#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */ ++#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */ ++#define PCIE_ASPMTIMER_EXTEND 0x01000000 ++ /* > rev7: ++ * enable extend ASPM timer ++ */ ++ ++/* different register spaces to access thru pcie indirect access */ ++#define PCIE_CONFIGREGS 1 /* Access to config space */ ++#define PCIE_PCIEREGS 2 /* Access to pcie registers */ ++ ++/* PCIE protocol PHY diagnostic registers */ ++#define PCIE_PLP_STATUSREG 0x204 /* Status */ ++ ++/* Status reg PCIE_PLP_STATUSREG */ ++#define PCIE_PLP_POLARITYINV_STAT 0x10 ++ ++/* PCIE protocol DLLP diagnostic registers */ ++#define PCIE_DLLP_LCREG 0x100 /* Link Control */ ++#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ ++ ++/* PCIE protocol TLP diagnostic registers */ ++#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ ++ ++/* Sonics to PCI translation types */ ++#define SBTOPCI_PREF 0x4 /* prefetch enable */ ++#define SBTOPCI_BURST 0x8 /* burst enable */ ++#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */ ++ ++#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */ ++ ++/* PCI core index in SROM shadow area */ ++#define SRSH_PI_OFFSET 0 /* first word */ ++#define SRSH_PI_MASK 0xf000 /* bit 15:12 */ ++#define SRSH_PI_SHIFT 12 /* bit 15:12 */ ++ ++/* Sonics side: PCI core and host control registers */ ++struct sbpciregs { ++ u32 control; /* PCI control */ ++ u32 PAD[3]; ++ u32 arbcontrol; /* PCI arbiter control */ ++ u32 clkrun; /* Clkrun Control (>=rev11) */ ++ u32 PAD[2]; ++ u32 intstatus; /* Interrupt status */ ++ u32 intmask; /* Interrupt mask */ ++ u32 sbtopcimailbox; /* Sonics to PCI mailbox */ ++ u32 PAD[9]; ++ u32 bcastaddr; /* Sonics broadcast address */ ++ u32 bcastdata; /* Sonics broadcast data */ ++ u32 PAD[2]; ++ u32 gpioin; /* ro: gpio input (>=rev2) */ ++ u32 gpioout; /* rw: gpio output (>=rev2) */ ++ u32 gpioouten; /* rw: gpio output enable (>= rev2) */ ++ u32 gpiocontrol; /* rw: gpio control (>= rev2) */ ++ u32 PAD[36]; ++ u32 sbtopci0; /* Sonics to PCI translation 0 */ ++ u32 sbtopci1; /* Sonics to PCI translation 1 */ ++ u32 sbtopci2; /* Sonics to PCI translation 2 */ ++ u32 PAD[189]; ++ u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */ ++ u16 sprom[36]; /* SPROM shadow Area */ ++ u32 PAD[46]; ++}; ++ ++/* SB side: PCIE core and host control registers */ ++struct sbpcieregs { ++ u32 control; /* host mode only */ ++ u32 PAD[2]; ++ u32 biststatus; /* bist Status: 0x00C */ ++ u32 gpiosel; /* PCIE gpio sel: 0x010 */ ++ u32 gpioouten; /* PCIE gpio outen: 0x14 */ ++ u32 PAD[2]; ++ u32 intstatus; /* Interrupt status: 0x20 */ ++ u32 intmask; /* Interrupt mask: 0x24 */ ++ u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ ++ u32 PAD[53]; ++ u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ ++ u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ ++ u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ ++ u32 PAD[5]; ++ ++ /* pcie core supports in direct access to config space */ ++ u32 configaddr; /* pcie config space access: Address field: 0x120 */ ++ u32 configdata; /* pcie config space access: Data field: 0x124 */ ++ ++ /* mdio access to serdes */ ++ u32 mdiocontrol; /* controls the mdio access: 0x128 */ ++ u32 mdiodata; /* Data to the mdio access: 0x12c */ ++ ++ /* pcie protocol phy/dllp/tlp register indirect access mechanism */ ++ u32 pcieindaddr; /* indirect access to ++ * the internal register: 0x130 ++ */ ++ u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ ++ ++ u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ ++ u32 PAD[177]; ++ u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */ ++ u16 sprom[64]; /* SPROM shadow Area */ ++}; ++ ++struct pcicore_info { ++ union { ++ struct sbpcieregs __iomem *pcieregs; ++ struct sbpciregs __iomem *pciregs; ++ } regs; /* Memory mapped register to the core */ ++ ++ struct si_pub *sih; /* System interconnect handle */ ++ struct pci_dev *dev; ++ u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset ++ * in the config space ++ */ ++ bool pcie_pr42767; ++ u8 pcie_polarity; ++ u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */ ++ ++ u8 pmecap_offset; /* PM Capability offset in the config space */ ++ bool pmecap; /* Capable of generating PME */ ++}; ++ ++#define PCIE_ASPM(sih) \ ++ (((sih)->buscoretype == PCIE_CORE_ID) && \ ++ (((sih)->buscorerev >= 3) && \ ++ ((sih)->buscorerev <= 5))) ++ ++ ++/* delay needed between the mdio control/ mdiodata register data access */ ++static void pr28829_delay(void) ++{ ++ udelay(10); ++} ++ ++/* Initialize the PCI core. ++ * It's caller's responsibility to make sure that this is done only once ++ */ ++struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev, ++ void __iomem *regs) ++{ ++ struct pcicore_info *pi; ++ ++ /* alloc struct pcicore_info */ ++ pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC); ++ if (pi == NULL) ++ return NULL; ++ ++ pi->sih = sih; ++ pi->dev = pdev; ++ ++ if (sih->buscoretype == PCIE_CORE_ID) { ++ u8 cap_ptr; ++ pi->regs.pcieregs = regs; ++ cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP, ++ NULL, NULL); ++ pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; ++ } else ++ pi->regs.pciregs = regs; ++ ++ return pi; ++} ++ ++void pcicore_deinit(struct pcicore_info *pch) ++{ ++ kfree(pch); ++} ++ ++/* return cap_offset if requested capability exists in the PCI config space */ ++/* Note that it's caller's responsibility to make sure it's a pci bus */ ++u8 ++pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, ++ unsigned char *buf, u32 *buflen) ++{ ++ u8 cap_id; ++ u8 cap_ptr = 0; ++ u32 bufsize; ++ u8 byte_val; ++ ++ /* check for Header type 0 */ ++ pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val); ++ if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL) ++ goto end; ++ ++ /* check if the capability pointer field exists */ ++ pci_read_config_byte(dev, PCI_STATUS, &byte_val); ++ if (!(byte_val & PCI_STATUS_CAP_LIST)) ++ goto end; ++ ++ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); ++ /* check if the capability pointer is 0x00 */ ++ if (cap_ptr == 0x00) ++ goto end; ++ ++ /* loop thru the capability list ++ * and see if the pcie capability exists ++ */ ++ ++ pci_read_config_byte(dev, cap_ptr, &cap_id); ++ ++ while (cap_id != req_cap_id) { ++ pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr); ++ if (cap_ptr == 0x00) ++ break; ++ pci_read_config_byte(dev, cap_ptr, &cap_id); ++ } ++ if (cap_id != req_cap_id) ++ goto end; ++ ++ /* found the caller requested capability */ ++ if (buf != NULL && buflen != NULL) { ++ u8 cap_data; ++ ++ bufsize = *buflen; ++ if (!bufsize) ++ goto end; ++ *buflen = 0; ++ /* copy the capability data excluding cap ID and next ptr */ ++ cap_data = cap_ptr + 2; ++ if ((bufsize + cap_data) > PCI_SZPCR) ++ bufsize = PCI_SZPCR - cap_data; ++ *buflen = bufsize; ++ while (bufsize--) { ++ pci_read_config_byte(dev, cap_data, buf); ++ cap_data++; ++ buf++; ++ } ++ } ++end: ++ return cap_ptr; ++} ++ ++/* ***** Register Access API */ ++static uint ++pcie_readreg(struct sbpcieregs __iomem *pcieregs, uint addrtype, uint offset) ++{ ++ uint retval = 0xFFFFFFFF; ++ ++ switch (addrtype) { ++ case PCIE_CONFIGREGS: ++ W_REG(&pcieregs->configaddr, offset); ++ (void)R_REG((&pcieregs->configaddr)); ++ retval = R_REG(&pcieregs->configdata); ++ break; ++ case PCIE_PCIEREGS: ++ W_REG(&pcieregs->pcieindaddr, offset); ++ (void)R_REG(&pcieregs->pcieindaddr); ++ retval = R_REG(&pcieregs->pcieinddata); ++ break; ++ } ++ ++ return retval; ++} ++ ++static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype, ++ uint offset, uint val) ++{ ++ switch (addrtype) { ++ case PCIE_CONFIGREGS: ++ W_REG((&pcieregs->configaddr), offset); ++ W_REG((&pcieregs->configdata), val); ++ break; ++ case PCIE_PCIEREGS: ++ W_REG((&pcieregs->pcieindaddr), offset); ++ W_REG((&pcieregs->pcieinddata), val); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) ++{ ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ uint mdiodata, i = 0; ++ uint pcie_serdes_spinwait = 200; ++ ++ mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | ++ (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | ++ (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | ++ (blk << 4)); ++ W_REG(&pcieregs->mdiodata, mdiodata); ++ ++ pr28829_delay(); ++ /* retry till the transaction is complete */ ++ while (i < pcie_serdes_spinwait) { ++ if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) ++ break; ++ ++ udelay(1000); ++ i++; ++ } ++ ++ if (i >= pcie_serdes_spinwait) ++ return false; ++ ++ return true; ++} ++ ++static int ++pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, ++ uint *val) ++{ ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ uint mdiodata; ++ uint i = 0; ++ uint pcie_serdes_spinwait = 10; ++ ++ /* enable mdio access to SERDES */ ++ W_REG(&pcieregs->mdiocontrol, MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); ++ ++ if (pi->sih->buscorerev >= 10) { ++ /* new serdes is slower in rw, ++ * using two layers of reg address mapping ++ */ ++ if (!pcie_mdiosetblock(pi, physmedia)) ++ return 1; ++ mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | ++ (regaddr << MDIODATA_REGADDR_SHF)); ++ pcie_serdes_spinwait *= 20; ++ } else { ++ mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) | ++ (regaddr << MDIODATA_REGADDR_SHF_OLD)); ++ } ++ ++ if (!write) ++ mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); ++ else ++ mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | ++ *val); ++ ++ W_REG(&pcieregs->mdiodata, mdiodata); ++ ++ pr28829_delay(); ++ ++ /* retry till the transaction is complete */ ++ while (i < pcie_serdes_spinwait) { ++ if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) { ++ if (!write) { ++ pr28829_delay(); ++ *val = (R_REG(&pcieregs->mdiodata) & ++ MDIODATA_MASK); ++ } ++ /* Disable mdio access to SERDES */ ++ W_REG(&pcieregs->mdiocontrol, 0); ++ return 0; ++ } ++ udelay(1000); ++ i++; ++ } ++ ++ /* Timed out. Disable mdio access to SERDES. */ ++ W_REG(&pcieregs->mdiocontrol, 0); ++ return 1; ++} ++ ++/* use the mdio interface to read from mdio slaves */ ++static int ++pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr, ++ uint *regval) ++{ ++ return pcie_mdioop(pi, physmedia, regaddr, false, regval); ++} ++ ++/* use the mdio interface to write to mdio slaves */ ++static int ++pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val) ++{ ++ return pcie_mdioop(pi, physmedia, regaddr, true, &val); ++} ++ ++/* ***** Support functions ***** */ ++static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val) ++{ ++ u32 reg_val; ++ u8 offset; ++ ++ offset = pi->pciecap_lcreg_offset; ++ if (!offset) ++ return 0; ++ ++ pci_read_config_dword(pi->dev, offset, ®_val); ++ /* set operation */ ++ if (mask) { ++ if (val) ++ reg_val |= PCIE_CLKREQ_ENAB; ++ else ++ reg_val &= ~PCIE_CLKREQ_ENAB; ++ pci_write_config_dword(pi->dev, offset, reg_val); ++ pci_read_config_dword(pi->dev, offset, ®_val); ++ } ++ if (reg_val & PCIE_CLKREQ_ENAB) ++ return 1; ++ else ++ return 0; ++} ++ ++static void pcie_extendL1timer(struct pcicore_info *pi, bool extend) ++{ ++ u32 w; ++ struct si_pub *sih = pi->sih; ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ ++ if (sih->buscoretype != PCIE_CORE_ID || sih->buscorerev < 7) ++ return; ++ ++ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); ++ if (extend) ++ w |= PCIE_ASPMTIMER_EXTEND; ++ else ++ w &= ~PCIE_ASPMTIMER_EXTEND; ++ pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); ++ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); ++} ++ ++/* centralized clkreq control policy */ ++static void pcie_clkreq_upd(struct pcicore_info *pi, uint state) ++{ ++ struct si_pub *sih = pi->sih; ++ ++ switch (state) { ++ case SI_DOATTACH: ++ if (PCIE_ASPM(sih)) ++ pcie_clkreq(pi, 1, 0); ++ break; ++ case SI_PCIDOWN: ++ if (sih->buscorerev == 6) { /* turn on serdes PLL down */ ++ ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_addr), ++ ~0, 0); ++ ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), ++ ~0x40, 0); ++ } else if (pi->pcie_pr42767) { ++ pcie_clkreq(pi, 1, 1); ++ } ++ break; ++ case SI_PCIUP: ++ if (sih->buscorerev == 6) { /* turn off serdes PLL down */ ++ ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_addr), ++ ~0, 0); ++ ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), ++ ~0x40, 0x40); ++ } else if (PCIE_ASPM(sih)) { /* disable clkreq */ ++ pcie_clkreq(pi, 1, 0); ++ } ++ break; ++ } ++} ++ ++/* ***** PCI core WARs ***** */ ++/* Done only once at attach time */ ++static void pcie_war_polarity(struct pcicore_info *pi) ++{ ++ u32 w; ++ ++ if (pi->pcie_polarity != 0) ++ return; ++ ++ w = pcie_readreg(pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG); ++ ++ /* Detect the current polarity at attach and force that polarity and ++ * disable changing the polarity ++ */ ++ if ((w & PCIE_PLP_POLARITYINV_STAT) == 0) ++ pi->pcie_polarity = SERDES_RX_CTRL_FORCE; ++ else ++ pi->pcie_polarity = (SERDES_RX_CTRL_FORCE | ++ SERDES_RX_CTRL_POLARITY); ++} ++ ++/* enable ASPM and CLKREQ if srom doesn't have it */ ++/* Needs to happen when update to shadow SROM is needed ++ * : Coming out of 'standby'/'hibernate' ++ * : If pcie_war_aspm_ovr state changed ++ */ ++static void pcie_war_aspm_clkreq(struct pcicore_info *pi) ++{ ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ struct si_pub *sih = pi->sih; ++ u16 val16; ++ u16 __iomem *reg16; ++ u32 w; ++ ++ if (!PCIE_ASPM(sih)) ++ return; ++ ++ /* bypass this on QT or VSIM */ ++ reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; ++ val16 = R_REG(reg16); ++ ++ val16 &= ~SRSH_ASPM_ENB; ++ if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB) ++ val16 |= SRSH_ASPM_ENB; ++ else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB) ++ val16 |= SRSH_ASPM_L1_ENB; ++ else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB) ++ val16 |= SRSH_ASPM_L0s_ENB; ++ ++ W_REG(reg16, val16); ++ ++ pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); ++ w &= ~PCIE_ASPM_ENAB; ++ w |= pi->pcie_war_aspm_ovr; ++ pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); ++ ++ reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; ++ val16 = R_REG(reg16); ++ ++ if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) { ++ val16 |= SRSH_CLKREQ_ENB; ++ pi->pcie_pr42767 = true; ++ } else ++ val16 &= ~SRSH_CLKREQ_ENB; ++ ++ W_REG(reg16, val16); ++} ++ ++/* Apply the polarity determined at the start */ ++/* Needs to happen when coming out of 'standby'/'hibernate' */ ++static void pcie_war_serdes(struct pcicore_info *pi) ++{ ++ u32 w = 0; ++ ++ if (pi->pcie_polarity != 0) ++ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL, ++ pi->pcie_polarity); ++ ++ pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w); ++ if (w & PLL_CTRL_FREQDET_EN) { ++ w &= ~PLL_CTRL_FREQDET_EN; ++ pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w); ++ } ++} ++ ++/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ ++/* Needs to happen when coming out of 'standby'/'hibernate' */ ++static void pcie_misc_config_fixup(struct pcicore_info *pi) ++{ ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ u16 val16; ++ u16 __iomem *reg16; ++ ++ reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG]; ++ val16 = R_REG(reg16); ++ ++ if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) { ++ val16 |= SRSH_L23READY_EXIT_NOPERST; ++ W_REG(reg16, val16); ++ } ++} ++ ++/* quick hack for testing */ ++/* Needs to happen when coming out of 'standby'/'hibernate' */ ++static void pcie_war_noplldown(struct pcicore_info *pi) ++{ ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ u16 __iomem *reg16; ++ ++ /* turn off serdes PLL down */ ++ ai_corereg(pi->sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol), ++ CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); ++ ++ /* clear srom shadow backdoor */ ++ reg16 = &pcieregs->sprom[SRSH_BD_OFFSET]; ++ W_REG(reg16, 0); ++} ++ ++/* Needs to happen when coming out of 'standby'/'hibernate' */ ++static void pcie_war_pci_setup(struct pcicore_info *pi) ++{ ++ struct si_pub *sih = pi->sih; ++ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; ++ u32 w; ++ ++ if (sih->buscorerev == 0 || sih->buscorerev == 1) { ++ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, ++ PCIE_TLP_WORKAROUNDSREG); ++ w |= 0x8; ++ pcie_writereg(pcieregs, PCIE_PCIEREGS, ++ PCIE_TLP_WORKAROUNDSREG, w); ++ } ++ ++ if (sih->buscorerev == 1) { ++ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG); ++ w |= 0x40; ++ pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w); ++ } ++ ++ if (sih->buscorerev == 0) { ++ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128); ++ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100); ++ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466); ++ } else if (PCIE_ASPM(sih)) { ++ /* Change the L1 threshold for better performance */ ++ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, ++ PCIE_DLLP_PMTHRESHREG); ++ w &= ~PCIE_L1THRESHOLDTIME_MASK; ++ w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT; ++ pcie_writereg(pcieregs, PCIE_PCIEREGS, ++ PCIE_DLLP_PMTHRESHREG, w); ++ ++ pcie_war_serdes(pi); ++ ++ pcie_war_aspm_clkreq(pi); ++ } else if (pi->sih->buscorerev == 7) ++ pcie_war_noplldown(pi); ++ ++ /* Note that the fix is actually in the SROM, ++ * that's why this is open-ended ++ */ ++ if (pi->sih->buscorerev >= 6) ++ pcie_misc_config_fixup(pi); ++} ++ ++/* ***** Functions called during driver state changes ***** */ ++void pcicore_attach(struct pcicore_info *pi, int state) ++{ ++ struct si_pub *sih = pi->sih; ++ u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2); ++ ++ /* Determine if this board needs override */ ++ if (PCIE_ASPM(sih)) { ++ if (bfl2 & BFL2_PCIEWAR_OVR) ++ pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB; ++ else ++ pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB; ++ } ++ ++ /* These need to happen in this order only */ ++ pcie_war_polarity(pi); ++ ++ pcie_war_serdes(pi); ++ ++ pcie_war_aspm_clkreq(pi); ++ ++ pcie_clkreq_upd(pi, state); ++ ++} ++ ++void pcicore_hwup(struct pcicore_info *pi) ++{ ++ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) ++ return; ++ ++ pcie_war_pci_setup(pi); ++} ++ ++void pcicore_up(struct pcicore_info *pi, int state) ++{ ++ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) ++ return; ++ ++ /* Restore L1 timer for better performance */ ++ pcie_extendL1timer(pi, true); ++ ++ pcie_clkreq_upd(pi, state); ++} ++ ++/* When the device is going to enter D3 state ++ * (or the system is going to enter S3/S4 states) ++ */ ++void pcicore_sleep(struct pcicore_info *pi) ++{ ++ u32 w; ++ ++ if (!pi || !PCIE_ASPM(pi->sih)) ++ return; ++ ++ pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); ++ w &= ~PCIE_CAP_LCREG_ASPML1; ++ pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); ++ ++ pi->pcie_pr42767 = false; ++} ++ ++void pcicore_down(struct pcicore_info *pi, int state) ++{ ++ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) ++ return; ++ ++ pcie_clkreq_upd(pi, state); ++ ++ /* Reduce L1 timer for better power savings */ ++ pcie_extendL1timer(pi, false); ++} ++ ++/* precondition: current core is sii->buscoretype */ ++static void pcicore_fixcfg(struct pcicore_info *pi, u16 __iomem *reg16) ++{ ++ struct si_info *sii = (struct si_info *)(pi->sih); ++ u16 val16; ++ uint pciidx; ++ ++ pciidx = ai_coreidx(&sii->pub); ++ val16 = R_REG(reg16); ++ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16)pciidx) { ++ val16 = (u16)(pciidx << SRSH_PI_SHIFT) | ++ (val16 & ~SRSH_PI_MASK); ++ W_REG(reg16, val16); ++ } ++} ++ ++void ++pcicore_fixcfg_pci(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) ++{ ++ pcicore_fixcfg(pi, &pciregs->sprom[SRSH_PI_OFFSET]); ++} ++ ++void pcicore_fixcfg_pcie(struct pcicore_info *pi, ++ struct sbpcieregs __iomem *pcieregs) ++{ ++ pcicore_fixcfg(pi, &pcieregs->sprom[SRSH_PI_OFFSET]); ++} ++ ++/* precondition: current core is pci core */ ++void ++pcicore_pci_setup(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) ++{ ++ u32 w; ++ ++ OR_REG(&pciregs->sbtopci2, SBTOPCI_PREF | SBTOPCI_BURST); ++ ++ if (((struct si_info *)(pi->sih))->pub.buscorerev >= 11) { ++ OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI); ++ w = R_REG(&pciregs->clkrun); ++ W_REG(&pciregs->clkrun, w | PCI_CLKRUN_DSBL); ++ w = R_REG(&pciregs->clkrun); ++ } ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h.orig 2011-11-09 13:46:58.252800545 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h 2011-11-09 13:47:17.005566104 -0500 +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_NICPCI_H_ ++#define _BRCM_NICPCI_H_ ++ ++#include "types.h" ++ ++/* PCI configuration address space size */ ++#define PCI_SZPCR 256 ++ ++/* Brcm PCI configuration registers */ ++/* backplane address space accessed by BAR0 */ ++#define PCI_BAR0_WIN 0x80 ++/* sprom property control */ ++#define PCI_SPROM_CONTROL 0x88 ++/* mask of PCI and other cores interrupts */ ++#define PCI_INT_MASK 0x94 ++/* backplane core interrupt mask bits offset */ ++#define PCI_SBIM_SHIFT 8 ++/* backplane address space accessed by second 4KB of BAR0 */ ++#define PCI_BAR0_WIN2 0xac ++/* pci config space gpio input (>=rev3) */ ++#define PCI_GPIO_IN 0xb0 ++/* pci config space gpio output (>=rev3) */ ++#define PCI_GPIO_OUT 0xb4 ++/* pci config space gpio output enable (>=rev3) */ ++#define PCI_GPIO_OUTEN 0xb8 ++ ++/* bar0 + 4K accesses external sprom */ ++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) ++/* bar0 + 6K accesses pci core registers */ ++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) ++/* ++ * pci core SB registers are at the end of the ++ * 8KB window, so their address is the "regular" ++ * address plus 4K ++ */ ++#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) ++/* bar0 window size Match with corerev 13 */ ++#define PCI_BAR0_WINSZ (16 * 1024) ++/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ ++/* bar0 + 8K accesses pci/pcie core registers */ ++#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) ++/* bar0 + 12K accesses chipc core registers */ ++#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) ++ ++struct sbpciregs; ++struct sbpcieregs; ++ ++extern struct pcicore_info *pcicore_init(struct si_pub *sih, ++ struct pci_dev *pdev, ++ void __iomem *regs); ++extern void pcicore_deinit(struct pcicore_info *pch); ++extern void pcicore_attach(struct pcicore_info *pch, int state); ++extern void pcicore_hwup(struct pcicore_info *pch); ++extern void pcicore_up(struct pcicore_info *pch, int state); ++extern void pcicore_sleep(struct pcicore_info *pch); ++extern void pcicore_down(struct pcicore_info *pch, int state); ++extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, ++ unsigned char *buf, u32 *buflen); ++extern void pcicore_fixcfg_pci(struct pcicore_info *pch, ++ struct sbpciregs __iomem *pciregs); ++extern void pcicore_fixcfg_pcie(struct pcicore_info *pch, ++ struct sbpcieregs __iomem *pciregs); ++extern void pcicore_pci_setup(struct pcicore_info *pch, ++ struct sbpciregs __iomem *pciregs); ++ ++#endif /* _BRCM_NICPCI_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.c.orig 2011-11-09 13:46:58.252800545 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.c 2011-11-09 13:47:17.006566092 -0500 +@@ -0,0 +1,426 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include "aiutils.h" ++#include "otp.h" ++ ++#define OTPS_GUP_MASK 0x00000f00 ++#define OTPS_GUP_SHIFT 8 ++/* h/w subregion is programmed */ ++#define OTPS_GUP_HW 0x00000100 ++/* s/w subregion is programmed */ ++#define OTPS_GUP_SW 0x00000200 ++/* chipid/pkgopt subregion is programmed */ ++#define OTPS_GUP_CI 0x00000400 ++/* fuse subregion is programmed */ ++#define OTPS_GUP_FUSE 0x00000800 ++ ++/* Fields in otpprog in rev >= 21 */ ++#define OTPP_COL_MASK 0x000000ff ++#define OTPP_COL_SHIFT 0 ++#define OTPP_ROW_MASK 0x0000ff00 ++#define OTPP_ROW_SHIFT 8 ++#define OTPP_OC_MASK 0x0f000000 ++#define OTPP_OC_SHIFT 24 ++#define OTPP_READERR 0x10000000 ++#define OTPP_VALUE_MASK 0x20000000 ++#define OTPP_VALUE_SHIFT 29 ++#define OTPP_START_BUSY 0x80000000 ++#define OTPP_READ 0x40000000 ++ ++/* Opcodes for OTPP_OC field */ ++#define OTPPOC_READ 0 ++#define OTPPOC_BIT_PROG 1 ++#define OTPPOC_VERIFY 3 ++#define OTPPOC_INIT 4 ++#define OTPPOC_SET 5 ++#define OTPPOC_RESET 6 ++#define OTPPOC_OCST 7 ++#define OTPPOC_ROW_LOCK 8 ++#define OTPPOC_PRESCN_TEST 9 ++ ++#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23) ++ ++#define OTPP_TRIES 10000000 /* # of tries for OTPP */ ++ ++#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */ ++ ++/* Fixed size subregions sizes in words */ ++#define OTPGU_CI_SZ 2 ++ ++struct otpinfo; ++ ++/* OTP function struct */ ++struct otp_fn_s { ++ int (*init)(struct si_pub *sih, struct otpinfo *oi); ++ int (*read_region)(struct otpinfo *oi, int region, u16 *data, ++ uint *wlen); ++}; ++ ++struct otpinfo { ++ uint ccrev; /* chipc revision */ ++ const struct otp_fn_s *fn; /* OTP functions */ ++ struct si_pub *sih; /* Saved sb handle */ ++ ++ /* IPX OTP section */ ++ u16 wsize; /* Size of otp in words */ ++ u16 rows; /* Geometry */ ++ u16 cols; /* Geometry */ ++ u32 status; /* Flag bits (lock/prog/rv). ++ * (Reflected only when OTP is power cycled) ++ */ ++ u16 hwbase; /* hardware subregion offset */ ++ u16 hwlim; /* hardware subregion boundary */ ++ u16 swbase; /* software subregion offset */ ++ u16 swlim; /* software subregion boundary */ ++ u16 fbase; /* fuse subregion offset */ ++ u16 flim; /* fuse subregion boundary */ ++ int otpgu_base; /* offset to General Use Region */ ++}; ++ ++/* OTP layout */ ++/* CC revs 21, 24 and 27 OTP General Use Region word offset */ ++#define REVA4_OTPGU_BASE 12 ++ ++/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */ ++#define REVB8_OTPGU_BASE 20 ++ ++/* CC rev 36 OTP General Use Region word offset */ ++#define REV36_OTPGU_BASE 12 ++ ++/* Subregion word offsets in General Use region */ ++#define OTPGU_HSB_OFF 0 ++#define OTPGU_SFB_OFF 1 ++#define OTPGU_CI_OFF 2 ++#define OTPGU_P_OFF 3 ++#define OTPGU_SROM_OFF 4 ++ ++/* Flag bit offsets in General Use region */ ++#define OTPGU_HWP_OFF 60 ++#define OTPGU_SWP_OFF 61 ++#define OTPGU_CIP_OFF 62 ++#define OTPGU_FUSEP_OFF 63 ++#define OTPGU_CIP_MSK 0x4000 ++#define OTPGU_P_MSK 0xf000 ++#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16) ++ ++/* OTP Size */ ++#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */ ++#define OTP_SZ_FU_288 (288/8) /* 288 bits */ ++#define OTP_SZ_FU_216 (216/8) /* 216 bits */ ++#define OTP_SZ_FU_72 (72/8) /* 72 bits */ ++#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */ ++#define OTP4315_SWREG_SZ 178 /* 178 bytes */ ++#define OTP_SZ_FU_144 (144/8) /* 144 bits */ ++ ++static u16 ++ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn) ++{ ++ return R_REG(&cc->sromotp[wn]); ++} ++ ++/* ++ * Calculate max HW/SW region byte size by subtracting fuse region ++ * and checksum size, osizew is oi->wsize (OTP size - GU size) in words ++ */ ++static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew) ++{ ++ int ret = 0; ++ ++ switch (sih->chip) { ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; ++ break; ++ case BCM4313_CHIP_ID: ++ ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; ++ break; ++ default: ++ break; /* Don't know about this chip */ ++ } ++ ++ return ret; ++} ++ ++static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) ++{ ++ uint k; ++ u32 otpp, st; ++ ++ /* ++ * record word offset of General Use Region ++ * for various chipcommon revs ++ */ ++ if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24 ++ || oi->sih->ccrev == 27) { ++ oi->otpgu_base = REVA4_OTPGU_BASE; ++ } else if (oi->sih->ccrev == 36) { ++ /* ++ * OTP size greater than equal to 2KB (128 words), ++ * otpgu_base is similar to rev23 ++ */ ++ if (oi->wsize >= 128) ++ oi->otpgu_base = REVB8_OTPGU_BASE; ++ else ++ oi->otpgu_base = REV36_OTPGU_BASE; ++ } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) { ++ oi->otpgu_base = REVB8_OTPGU_BASE; ++ } ++ ++ /* First issue an init command so the status is up to date */ ++ otpp = ++ OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK); ++ ++ W_REG(&cc->otpprog, otpp); ++ for (k = 0; ++ ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY) ++ && (k < OTPP_TRIES); k++) ++ ; ++ if (k >= OTPP_TRIES) ++ return; ++ ++ /* Read OTP lock bits and subregion programmed indication bits */ ++ oi->status = R_REG(&cc->otpstatus); ++ ++ if ((oi->sih->chip == BCM43224_CHIP_ID) ++ || (oi->sih->chip == BCM43225_CHIP_ID)) { ++ u32 p_bits; ++ p_bits = ++ (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) & ++ OTPGU_P_MSK) ++ >> OTPGU_P_SHIFT; ++ oi->status |= (p_bits << OTPS_GUP_SHIFT); ++ } ++ ++ /* ++ * h/w region base and fuse region limit are fixed to ++ * the top and the bottom of the general use region. ++ * Everything else can be flexible. ++ */ ++ oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF; ++ oi->hwlim = oi->wsize; ++ if (oi->status & OTPS_GUP_HW) { ++ oi->hwlim = ++ ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16; ++ oi->swbase = oi->hwlim; ++ } else ++ oi->swbase = oi->hwbase; ++ ++ /* subtract fuse and checksum from beginning */ ++ oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2; ++ ++ if (oi->status & OTPS_GUP_SW) { ++ oi->swlim = ++ ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16; ++ oi->fbase = oi->swlim; ++ } else ++ oi->fbase = oi->swbase; ++ ++ oi->flim = oi->wsize; ++} ++ ++static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) ++{ ++ uint idx; ++ struct chipcregs __iomem *cc; ++ ++ /* Make sure we're running IPX OTP */ ++ if (!OTPTYPE_IPX(sih->ccrev)) ++ return -EBADE; ++ ++ /* Make sure OTP is not disabled */ ++ if (ai_is_otp_disabled(sih)) ++ return -EBADE; ++ ++ /* Check for otp size */ ++ switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { ++ case 0: ++ /* Nothing there */ ++ return -EBADE; ++ case 1: /* 32x64 */ ++ oi->rows = 32; ++ oi->cols = 64; ++ oi->wsize = 128; ++ break; ++ case 2: /* 64x64 */ ++ oi->rows = 64; ++ oi->cols = 64; ++ oi->wsize = 256; ++ break; ++ case 5: /* 96x64 */ ++ oi->rows = 96; ++ oi->cols = 64; ++ oi->wsize = 384; ++ break; ++ case 7: /* 16x64 *//* 1024 bits */ ++ oi->rows = 16; ++ oi->cols = 64; ++ oi->wsize = 64; ++ break; ++ default: ++ /* Don't know the geometry */ ++ return -EBADE; ++ } ++ ++ /* Retrieve OTP region info */ ++ idx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ _ipxotp_init(oi, cc); ++ ++ ai_setcoreidx(sih, idx); ++ ++ return 0; ++} ++ ++static int ++ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen) ++{ ++ uint idx; ++ struct chipcregs __iomem *cc; ++ uint base, i, sz; ++ ++ /* Validate region selection */ ++ switch (region) { ++ case OTP_HW_RGN: ++ sz = (uint) oi->hwlim - oi->hwbase; ++ if (!(oi->status & OTPS_GUP_HW)) { ++ *wlen = sz; ++ return -ENODATA; ++ } ++ if (*wlen < sz) { ++ *wlen = sz; ++ return -EOVERFLOW; ++ } ++ base = oi->hwbase; ++ break; ++ case OTP_SW_RGN: ++ sz = ((uint) oi->swlim - oi->swbase); ++ if (!(oi->status & OTPS_GUP_SW)) { ++ *wlen = sz; ++ return -ENODATA; ++ } ++ if (*wlen < sz) { ++ *wlen = sz; ++ return -EOVERFLOW; ++ } ++ base = oi->swbase; ++ break; ++ case OTP_CI_RGN: ++ sz = OTPGU_CI_SZ; ++ if (!(oi->status & OTPS_GUP_CI)) { ++ *wlen = sz; ++ return -ENODATA; ++ } ++ if (*wlen < sz) { ++ *wlen = sz; ++ return -EOVERFLOW; ++ } ++ base = oi->otpgu_base + OTPGU_CI_OFF; ++ break; ++ case OTP_FUSE_RGN: ++ sz = (uint) oi->flim - oi->fbase; ++ if (!(oi->status & OTPS_GUP_FUSE)) { ++ *wlen = sz; ++ return -ENODATA; ++ } ++ if (*wlen < sz) { ++ *wlen = sz; ++ return -EOVERFLOW; ++ } ++ base = oi->fbase; ++ break; ++ case OTP_ALL_RGN: ++ sz = ((uint) oi->flim - oi->hwbase); ++ if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) { ++ *wlen = sz; ++ return -ENODATA; ++ } ++ if (*wlen < sz) { ++ *wlen = sz; ++ return -EOVERFLOW; ++ } ++ base = oi->hwbase; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ idx = ai_coreidx(oi->sih); ++ cc = ai_setcoreidx(oi->sih, SI_CC_IDX); ++ ++ /* Read the data */ ++ for (i = 0; i < sz; i++) ++ data[i] = ipxotp_otpr(oi, cc, base + i); ++ ++ ai_setcoreidx(oi->sih, idx); ++ *wlen = sz; ++ return 0; ++} ++ ++static const struct otp_fn_s ipxotp_fn = { ++ (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init, ++ (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region, ++}; ++ ++static int otp_init(struct si_pub *sih, struct otpinfo *oi) ++{ ++ ++ int ret; ++ ++ memset(oi, 0, sizeof(struct otpinfo)); ++ ++ oi->ccrev = sih->ccrev; ++ ++ if (OTPTYPE_IPX(oi->ccrev)) ++ oi->fn = &ipxotp_fn; ++ ++ if (oi->fn == NULL) ++ return -EBADE; ++ ++ oi->sih = sih; ++ ++ ret = (oi->fn->init) (sih, oi); ++ ++ return ret; ++} ++ ++int ++otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) { ++ struct otpinfo otpinfo; ++ struct otpinfo *oi = &otpinfo; ++ int err = 0; ++ ++ if (ai_is_otp_disabled(sih)) { ++ err = -EPERM; ++ goto out; ++ } ++ ++ err = otp_init(sih, oi); ++ if (err) ++ goto out; ++ ++ err = ((oi)->fn->read_region)(oi, region, data, wlen); ++ ++ out: ++ return err; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.h.orig 2011-11-09 13:46:58.252800545 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/otp.h 2011-11-09 13:47:17.006566092 -0500 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_OTP_H_ ++#define _BRCM_OTP_H_ ++ ++#include "types.h" ++ ++/* OTP regions */ ++#define OTP_HW_RGN 1 ++#define OTP_SW_RGN 2 ++#define OTP_CI_RGN 4 ++#define OTP_FUSE_RGN 8 ++/* From h/w region to end of OTP including checksum */ ++#define OTP_ALL_RGN 0xf ++ ++/* OTP Size */ ++#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */ ++ ++extern int otp_read_region(struct si_pub *sih, int region, u16 *data, ++ uint *wlen); ++ ++#endif /* _BRCM_OTP_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c.orig 2011-11-09 13:46:58.254800521 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c 2011-11-09 13:47:17.008566067 -0500 +@@ -0,0 +1,2988 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include "phy_hal.h" ++#include "phy_int.h" ++#include "phy_radio.h" ++#include "phy_lcn.h" ++#include "phyreg_n.h" ++ ++#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \ ++ (radioid == BCM2056_ID) || \ ++ (radioid == BCM2057_ID)) ++ ++#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID) ++ ++#define VALID_RADIO(pi, radioid) ( \ ++ (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \ ++ (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false)) ++ ++/* basic mux operation - can be optimized on several architectures */ ++#define MUX(pred, true, false) ((pred) ? (true) : (false)) ++ ++/* modulo inc/dec - assumes x E [0, bound - 1] */ ++#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) ++ ++/* modulo inc/dec, bound = 2^k */ ++#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) ++#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) ++ ++struct chan_info_basic { ++ u16 chan; ++ u16 freq; ++}; ++ ++static const struct chan_info_basic chan_info_all[] = { ++ {1, 2412}, ++ {2, 2417}, ++ {3, 2422}, ++ {4, 2427}, ++ {5, 2432}, ++ {6, 2437}, ++ {7, 2442}, ++ {8, 2447}, ++ {9, 2452}, ++ {10, 2457}, ++ {11, 2462}, ++ {12, 2467}, ++ {13, 2472}, ++ {14, 2484}, ++ ++ {34, 5170}, ++ {38, 5190}, ++ {42, 5210}, ++ {46, 5230}, ++ ++ {36, 5180}, ++ {40, 5200}, ++ {44, 5220}, ++ {48, 5240}, ++ {52, 5260}, ++ {56, 5280}, ++ {60, 5300}, ++ {64, 5320}, ++ ++ {100, 5500}, ++ {104, 5520}, ++ {108, 5540}, ++ {112, 5560}, ++ {116, 5580}, ++ {120, 5600}, ++ {124, 5620}, ++ {128, 5640}, ++ {132, 5660}, ++ {136, 5680}, ++ {140, 5700}, ++ ++ {149, 5745}, ++ {153, 5765}, ++ {157, 5785}, ++ {161, 5805}, ++ {165, 5825}, ++ ++ {184, 4920}, ++ {188, 4940}, ++ {192, 4960}, ++ {196, 4980}, ++ {200, 5000}, ++ {204, 5020}, ++ {208, 5040}, ++ {212, 5060}, ++ {216, 50800} ++}; ++ ++const u8 ofdm_rate_lookup[] = { ++ ++ BRCM_RATE_48M, ++ BRCM_RATE_24M, ++ BRCM_RATE_12M, ++ BRCM_RATE_6M, ++ BRCM_RATE_54M, ++ BRCM_RATE_36M, ++ BRCM_RATE_18M, ++ BRCM_RATE_9M ++}; ++ ++#define PHY_WREG_LIMIT 24 ++ ++void wlc_phyreg_enter(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim); ++} ++ ++void wlc_phyreg_exit(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); ++} ++ ++void wlc_radioreg_enter(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); ++ ++ udelay(10); ++} ++ ++void wlc_radioreg_exit(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ u16 dummy; ++ ++ dummy = R_REG(&pi->regs->phyversion); ++ pi->phy_wreg = 0; ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); ++} ++ ++u16 read_radio_reg(struct brcms_phy *pi, u16 addr) ++{ ++ u16 data; ++ ++ if ((addr == RADIO_IDCODE)) ++ return 0xffff; ++ ++ switch (pi->pubpi.phy_type) { ++ case PHY_TYPE_N: ++ if (!CONF_HAS(PHYTYPE, PHY_TYPE_N)) ++ break; ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ addr |= RADIO_2057_READ_OFF; ++ else ++ addr |= RADIO_2055_READ_OFF; ++ break; ++ ++ case PHY_TYPE_LCN: ++ if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN)) ++ break; ++ addr |= RADIO_2064_READ_OFF; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if ((D11REV_GE(pi->sh->corerev, 24)) || ++ (D11REV_IS(pi->sh->corerev, 22) ++ && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { ++ W_REG_FLUSH(&pi->regs->radioregaddr, addr); ++ data = R_REG(&pi->regs->radioregdata); ++ } else { ++ W_REG_FLUSH(&pi->regs->phy4waddr, addr); ++ ++#ifdef __ARM_ARCH_4T__ ++ __asm__(" .align 4 "); ++ __asm__(" nop "); ++ data = R_REG(&pi->regs->phy4wdatalo); ++#else ++ data = R_REG(&pi->regs->phy4wdatalo); ++#endif ++ ++ } ++ pi->phy_wreg = 0; ++ ++ return data; ++} ++ ++void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ if ((D11REV_GE(pi->sh->corerev, 24)) || ++ (D11REV_IS(pi->sh->corerev, 22) ++ && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { ++ ++ W_REG_FLUSH(&pi->regs->radioregaddr, addr); ++ W_REG(&pi->regs->radioregdata, val); ++ } else { ++ W_REG_FLUSH(&pi->regs->phy4waddr, addr); ++ W_REG(&pi->regs->phy4wdatalo, val); ++ } ++ ++ if (++pi->phy_wreg >= pi->phy_wreg_limit) { ++ (void)R_REG(&pi->regs->maccontrol); ++ pi->phy_wreg = 0; ++ } ++} ++ ++static u32 read_radio_id(struct brcms_phy *pi) ++{ ++ u32 id; ++ ++ if (D11REV_GE(pi->sh->corerev, 24)) { ++ u32 b0, b1, b2; ++ ++ W_REG_FLUSH(&pi->regs->radioregaddr, 0); ++ b0 = (u32) R_REG(&pi->regs->radioregdata); ++ W_REG_FLUSH(&pi->regs->radioregaddr, 1); ++ b1 = (u32) R_REG(&pi->regs->radioregdata); ++ W_REG_FLUSH(&pi->regs->radioregaddr, 2); ++ b2 = (u32) R_REG(&pi->regs->radioregdata); ++ ++ id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4) ++ & 0xf); ++ } else { ++ W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE); ++ id = (u32) R_REG(&pi->regs->phy4wdatalo); ++ id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16; ++ } ++ pi->phy_wreg = 0; ++ return id; ++} ++ ++void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ u16 rval; ++ ++ rval = read_radio_reg(pi, addr); ++ write_radio_reg(pi, addr, (rval & val)); ++} ++ ++void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ u16 rval; ++ ++ rval = read_radio_reg(pi, addr); ++ write_radio_reg(pi, addr, (rval | val)); ++} ++ ++void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask) ++{ ++ u16 rval; ++ ++ rval = read_radio_reg(pi, addr); ++ write_radio_reg(pi, addr, (rval ^ mask)); ++} ++ ++void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) ++{ ++ u16 rval; ++ ++ rval = read_radio_reg(pi, addr); ++ write_radio_reg(pi, addr, (rval & ~mask) | (val & mask)); ++} ++ ++void write_phy_channel_reg(struct brcms_phy *pi, uint val) ++{ ++ W_REG(&pi->regs->phychannel, val); ++} ++ ++u16 read_phy_reg(struct brcms_phy *pi, u16 addr) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = pi->regs; ++ ++ W_REG_FLUSH(®s->phyregaddr, addr); ++ ++ pi->phy_wreg = 0; ++ return R_REG(®s->phyregdata); ++} ++ ++void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = pi->regs; ++ ++#ifdef CONFIG_BCM47XX ++ W_REG_FLUSH(®s->phyregaddr, addr); ++ W_REG(®s->phyregdata, val); ++ if (addr == 0x72) ++ (void)R_REG(®s->phyregdata); ++#else ++ W_REG((u32 __iomem *)(®s->phyregaddr), addr | (val << 16)); ++ if (++pi->phy_wreg >= pi->phy_wreg_limit) { ++ pi->phy_wreg = 0; ++ (void)R_REG(®s->phyversion); ++ } ++#endif ++} ++ ++void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = pi->regs; ++ ++ W_REG_FLUSH(®s->phyregaddr, addr); ++ ++ W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val)); ++ pi->phy_wreg = 0; ++} ++ ++void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = pi->regs; ++ ++ W_REG_FLUSH(®s->phyregaddr, addr); ++ ++ W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val)); ++ pi->phy_wreg = 0; ++} ++ ++void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) ++{ ++ struct d11regs __iomem *regs; ++ ++ regs = pi->regs; ++ ++ W_REG_FLUSH(®s->phyregaddr, addr); ++ ++ W_REG(®s->phyregdata, ++ ((R_REG(®s->phyregdata) & ~mask) | (val & mask))); ++ pi->phy_wreg = 0; ++} ++ ++static void wlc_set_phy_uninitted(struct brcms_phy *pi) ++{ ++ int i, j; ++ ++ pi->initialized = false; ++ ++ pi->tx_vos = 0xffff; ++ pi->nrssi_table_delta = 0x7fffffff; ++ pi->rc_cal = 0xffff; ++ pi->mintxbias = 0xffff; ++ pi->txpwridx = -1; ++ if (ISNPHY(pi)) { ++ pi->phy_spuravoid = SPURAVOID_DISABLE; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) ++ && NREV_LT(pi->pubpi.phy_rev, 7)) ++ pi->phy_spuravoid = SPURAVOID_AUTO; ++ ++ pi->nphy_papd_skip = 0; ++ pi->nphy_papd_epsilon_offset[0] = 0xf588; ++ pi->nphy_papd_epsilon_offset[1] = 0xf588; ++ pi->nphy_txpwr_idx[0] = 128; ++ pi->nphy_txpwr_idx[1] = 128; ++ pi->nphy_txpwrindex[0].index_internal = 40; ++ pi->nphy_txpwrindex[1].index_internal = 40; ++ pi->phy_pabias = 0; ++ } else { ++ pi->phy_spuravoid = SPURAVOID_AUTO; ++ } ++ pi->radiopwr = 0xffff; ++ for (i = 0; i < STATIC_NUM_RF; i++) { ++ for (j = 0; j < STATIC_NUM_BB; j++) ++ pi->stats_11b_txpower[i][j] = -1; ++ } ++} ++ ++struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) ++{ ++ struct shared_phy *sh; ++ ++ sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC); ++ if (sh == NULL) ++ return NULL; ++ ++ sh->sih = shp->sih; ++ sh->physhim = shp->physhim; ++ sh->unit = shp->unit; ++ sh->corerev = shp->corerev; ++ ++ sh->vid = shp->vid; ++ sh->did = shp->did; ++ sh->chip = shp->chip; ++ sh->chiprev = shp->chiprev; ++ sh->chippkg = shp->chippkg; ++ sh->sromrev = shp->sromrev; ++ sh->boardtype = shp->boardtype; ++ sh->boardrev = shp->boardrev; ++ sh->boardvendor = shp->boardvendor; ++ sh->boardflags = shp->boardflags; ++ sh->boardflags2 = shp->boardflags2; ++ sh->buscorerev = shp->buscorerev; ++ ++ sh->fast_timer = PHY_SW_TIMER_FAST; ++ sh->slow_timer = PHY_SW_TIMER_SLOW; ++ sh->glacial_timer = PHY_SW_TIMER_GLACIAL; ++ ++ sh->rssi_mode = RSSI_ANT_MERGE_MAX; ++ ++ return sh; ++} ++ ++static void wlc_phy_timercb_phycal(struct brcms_phy *pi) ++{ ++ uint delay = 5; ++ ++ if (PHY_PERICAL_MPHASE_PENDING(pi)) { ++ if (!pi->sh->up) { ++ wlc_phy_cal_perical_mphase_reset(pi); ++ return; ++ } ++ ++ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) { ++ ++ delay = 1000; ++ wlc_phy_cal_perical_mphase_restart(pi); ++ } else ++ wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO); ++ wlapi_add_timer(pi->phycal_timer, delay, 0); ++ return; ++ } ++ ++} ++ ++static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi) ++{ ++ u32 ver; ++ ++ ver = read_radio_id(pi); ++ ++ return ver; ++} ++ ++struct brcms_phy_pub * ++wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, ++ int bandtype, struct wiphy *wiphy) ++{ ++ struct brcms_phy *pi; ++ u32 sflags = 0; ++ uint phyversion; ++ u32 idcode; ++ int i; ++ ++ if (D11REV_IS(sh->corerev, 4)) ++ sflags = SISF_2G_PHY | SISF_5G_PHY; ++ else ++ sflags = ai_core_sflags(sh->sih, 0, 0); ++ ++ if (bandtype == BRCM_BAND_5G) { ++ if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) ++ return NULL; ++ } ++ ++ pi = sh->phy_head; ++ if ((sflags & SISF_DB_PHY) && pi) { ++ wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); ++ pi->refcnt++; ++ return &pi->pubpi_ro; ++ } ++ ++ pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC); ++ if (pi == NULL) ++ return NULL; ++ pi->wiphy = wiphy; ++ pi->regs = regs; ++ pi->sh = sh; ++ pi->phy_init_por = true; ++ pi->phy_wreg_limit = PHY_WREG_LIMIT; ++ ++ pi->txpwr_percent = 100; ++ ++ pi->do_initcal = true; ++ ++ pi->phycal_tempdelta = 0; ++ ++ if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY)) ++ pi->pubpi.coreflags = SICF_GMODE; ++ ++ wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); ++ phyversion = R_REG(&pi->regs->phyversion); ++ ++ pi->pubpi.phy_type = PHY_TYPE(phyversion); ++ pi->pubpi.phy_rev = phyversion & PV_PV_MASK; ++ ++ if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) { ++ pi->pubpi.phy_type = PHY_TYPE_N; ++ pi->pubpi.phy_rev += LCNXN_BASEREV; ++ } ++ pi->pubpi.phy_corenum = PHY_CORE_NUM_2; ++ pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT; ++ ++ if (!pi->pubpi.phy_type == PHY_TYPE_N && ++ !pi->pubpi.phy_type == PHY_TYPE_LCN) ++ goto err; ++ ++ if (bandtype == BRCM_BAND_5G) { ++ if (!ISNPHY(pi)) ++ goto err; ++ } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) { ++ goto err; ++ } ++ ++ wlc_phy_anacore((struct brcms_phy_pub *) pi, ON); ++ ++ idcode = wlc_phy_get_radio_ver(pi); ++ pi->pubpi.radioid = ++ (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT; ++ pi->pubpi.radiorev = ++ (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT; ++ pi->pubpi.radiover = ++ (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT; ++ if (!VALID_RADIO(pi, pi->pubpi.radioid)) ++ goto err; ++ ++ wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF); ++ ++ wlc_set_phy_uninitted(pi); ++ ++ pi->bw = WL_CHANSPEC_BW_20; ++ pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ? ++ ch20mhz_chspec(1) : ch20mhz_chspec(36); ++ ++ pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; ++ pi->rxiq_antsel = ANT_RX_DIV_DEF; ++ ++ pi->watchdog_override = true; ++ ++ pi->cal_type_override = PHY_PERICAL_AUTO; ++ ++ pi->nphy_saved_noisevars.bufcount = 0; ++ ++ if (ISNPHY(pi)) ++ pi->min_txpower = PHY_TXPWR_MIN_NPHY; ++ else ++ pi->min_txpower = PHY_TXPWR_MIN; ++ ++ pi->sh->phyrxchain = 0x3; ++ ++ pi->rx2tx_biasentry = -1; ++ ++ pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; ++ pi->phy_txcore_enable_temp = ++ PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP; ++ pi->phy_tempsense_offset = 0; ++ pi->phy_txcore_heatedup = false; ++ ++ pi->nphy_lastcal_temp = -50; ++ ++ pi->phynoise_polling = true; ++ if (ISNPHY(pi) || ISLCNPHY(pi)) ++ pi->phynoise_polling = false; ++ ++ for (i = 0; i < TXP_NUM_RATES; i++) { ++ pi->txpwr_limit[i] = BRCMS_TXPWR_MAX; ++ pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; ++ pi->tx_user_target[i] = BRCMS_TXPWR_MAX; ++ } ++ ++ pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF; ++ ++ pi->user_txpwr_at_rfport = false; ++ ++ if (ISNPHY(pi)) { ++ ++ pi->phycal_timer = wlapi_init_timer(pi->sh->physhim, ++ wlc_phy_timercb_phycal, ++ pi, "phycal"); ++ if (!pi->phycal_timer) ++ goto err; ++ ++ if (!wlc_phy_attach_nphy(pi)) ++ goto err; ++ ++ } else if (ISLCNPHY(pi)) { ++ if (!wlc_phy_attach_lcnphy(pi)) ++ goto err; ++ ++ } ++ ++ pi->refcnt++; ++ pi->next = pi->sh->phy_head; ++ sh->phy_head = pi; ++ ++ memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub)); ++ ++ return &pi->pubpi_ro; ++ ++err: ++ kfree(pi); ++ return NULL; ++} ++ ++void wlc_phy_detach(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (pih) { ++ if (--pi->refcnt) ++ return; ++ ++ if (pi->phycal_timer) { ++ wlapi_free_timer(pi->phycal_timer); ++ pi->phycal_timer = NULL; ++ } ++ ++ if (pi->sh->phy_head == pi) ++ pi->sh->phy_head = pi->next; ++ else if (pi->sh->phy_head->next == pi) ++ pi->sh->phy_head->next = NULL; ++ ++ if (pi->pi_fptr.detach) ++ (pi->pi_fptr.detach)(pi); ++ ++ kfree(pi); ++ } ++} ++ ++bool ++wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, ++ u16 *radioid, u16 *radiover) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ *phytype = (u16) pi->pubpi.phy_type; ++ *phyrev = (u16) pi->pubpi.phy_rev; ++ *radioid = pi->pubpi.radioid; ++ *radiover = pi->pubpi.radiorev; ++ ++ return true; ++} ++ ++bool wlc_phy_get_encore(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ return pi->pubpi.abgphy_encore; ++} ++ ++u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ return pi->pubpi.coreflags; ++} ++ ++void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (ISNPHY(pi)) { ++ if (on) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0xa6, 0x0d); ++ write_phy_reg(pi, 0x8f, 0x0); ++ write_phy_reg(pi, 0xa7, 0x0d); ++ write_phy_reg(pi, 0xa5, 0x0); ++ } else { ++ write_phy_reg(pi, 0xa5, 0x0); ++ } ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0x8f, 0x07ff); ++ write_phy_reg(pi, 0xa6, 0x0fd); ++ write_phy_reg(pi, 0xa5, 0x07ff); ++ write_phy_reg(pi, 0xa7, 0x0fd); ++ } else { ++ write_phy_reg(pi, 0xa5, 0x7fff); ++ } ++ } ++ } else if (ISLCNPHY(pi)) { ++ if (on) { ++ and_phy_reg(pi, 0x43b, ++ ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); ++ } else { ++ or_phy_reg(pi, 0x43c, ++ (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); ++ or_phy_reg(pi, 0x43b, ++ (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); ++ } ++ } ++} ++ ++u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ u32 phy_bw_clkbits = 0; ++ ++ if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) { ++ switch (pi->bw) { ++ case WL_CHANSPEC_BW_10: ++ phy_bw_clkbits = SICF_BW10; ++ break; ++ case WL_CHANSPEC_BW_20: ++ phy_bw_clkbits = SICF_BW20; ++ break; ++ case WL_CHANSPEC_BW_40: ++ phy_bw_clkbits = SICF_BW40; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return phy_bw_clkbits; ++} ++ ++void wlc_phy_por_inform(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->phy_init_por = true; ++} ++ ++void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->edcrs_threshold_lock = lock; ++ ++ write_phy_reg(pi, 0x22c, 0x46b); ++ write_phy_reg(pi, 0x22d, 0x46b); ++ write_phy_reg(pi, 0x22e, 0x3c0); ++ write_phy_reg(pi, 0x22f, 0x3c0); ++} ++ ++void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->do_initcal = initcal; ++} ++ ++void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (!pi || !pi->sh) ++ return; ++ ++ pi->sh->clk = newstate; ++} ++ ++void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (!pi || !pi->sh) ++ return; ++ ++ pi->sh->up = newstate; ++} ++ ++void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) ++{ ++ u32 mc; ++ void (*phy_init)(struct brcms_phy *) = NULL; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (pi->init_in_progress) ++ return; ++ ++ pi->init_in_progress = true; ++ ++ pi->radio_chanspec = chanspec; ++ ++ mc = R_REG(&pi->regs->maccontrol); ++ if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init")) ++ return; ++ ++ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) ++ pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; ++ ++ if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA), ++ "HW error SISF_FCLKA\n")) ++ return; ++ ++ phy_init = pi->pi_fptr.init; ++ ++ if (phy_init == NULL) ++ return; ++ ++ wlc_phy_anacore(pih, ON); ++ ++ if (CHSPEC_BW(pi->radio_chanspec) != pi->bw) ++ wlapi_bmac_bw_set(pi->sh->physhim, ++ CHSPEC_BW(pi->radio_chanspec)); ++ ++ pi->nphy_gain_boost = true; ++ ++ wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON); ++ ++ (*phy_init)(pi); ++ ++ pi->phy_init_por = false; ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) ++ wlc_phy_do_dummy_tx(pi, true, OFF); ++ ++ if (!(ISNPHY(pi))) ++ wlc_phy_txpower_update_shm(pi); ++ ++ wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv); ++ ++ pi->init_in_progress = false; ++} ++ ++void wlc_phy_cal_init(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ void (*cal_init)(struct brcms_phy *) = NULL; ++ ++ if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0, ++ "HW error: MAC enabled during phy cal\n")) ++ return; ++ ++ if (!pi->initialized) { ++ cal_init = pi->pi_fptr.calinit; ++ if (cal_init) ++ (*cal_init)(pi); ++ ++ pi->initialized = true; ++ } ++} ++ ++int wlc_phy_down(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ int callbacks = 0; ++ ++ if (pi->phycal_timer ++ && !wlapi_del_timer(pi->phycal_timer)) ++ callbacks++; ++ ++ pi->nphy_iqcal_chanspec_2G = 0; ++ pi->nphy_iqcal_chanspec_5G = 0; ++ ++ return callbacks; ++} ++ ++void ++wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, ++ u16 tblAddr, u16 tblDataHi, u16 tblDataLo) ++{ ++ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); ++ ++ pi->tbl_data_hi = tblDataHi; ++ pi->tbl_data_lo = tblDataLo; ++ ++ if (pi->sh->chip == BCM43224_CHIP_ID && ++ pi->sh->chiprev == 1) { ++ pi->tbl_addr = tblAddr; ++ pi->tbl_save_id = tbl_id; ++ pi->tbl_save_offset = tbl_offset; ++ } ++} ++ ++void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) ++{ ++ if ((pi->sh->chip == BCM43224_CHIP_ID) && ++ (pi->sh->chiprev == 1) && ++ (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { ++ read_phy_reg(pi, pi->tbl_data_lo); ++ ++ write_phy_reg(pi, pi->tbl_addr, ++ (pi->tbl_save_id << 10) | pi->tbl_save_offset); ++ pi->tbl_save_offset++; ++ } ++ ++ if (width == 32) { ++ write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16)); ++ write_phy_reg(pi, pi->tbl_data_lo, (u16) val); ++ } else { ++ write_phy_reg(pi, pi->tbl_data_lo, (u16) val); ++ } ++} ++ ++void ++wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, ++ u16 tblAddr, u16 tblDataHi, u16 tblDataLo) ++{ ++ uint idx; ++ uint tbl_id = ptbl_info->tbl_id; ++ uint tbl_offset = ptbl_info->tbl_offset; ++ uint tbl_width = ptbl_info->tbl_width; ++ const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr; ++ const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr; ++ const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr; ++ ++ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); ++ ++ for (idx = 0; idx < ptbl_info->tbl_len; idx++) { ++ ++ if ((pi->sh->chip == BCM43224_CHIP_ID) && ++ (pi->sh->chiprev == 1) && ++ (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { ++ read_phy_reg(pi, tblDataLo); ++ ++ write_phy_reg(pi, tblAddr, ++ (tbl_id << 10) | (tbl_offset + idx)); ++ } ++ ++ if (tbl_width == 32) { ++ write_phy_reg(pi, tblDataHi, ++ (u16) (ptbl_32b[idx] >> 16)); ++ write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]); ++ } else if (tbl_width == 16) { ++ write_phy_reg(pi, tblDataLo, ptbl_16b[idx]); ++ } else { ++ write_phy_reg(pi, tblDataLo, ptbl_8b[idx]); ++ } ++ } ++} ++ ++void ++wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, ++ u16 tblAddr, u16 tblDataHi, u16 tblDataLo) ++{ ++ uint idx; ++ uint tbl_id = ptbl_info->tbl_id; ++ uint tbl_offset = ptbl_info->tbl_offset; ++ uint tbl_width = ptbl_info->tbl_width; ++ u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr; ++ u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr; ++ u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr; ++ ++ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); ++ ++ for (idx = 0; idx < ptbl_info->tbl_len; idx++) { ++ ++ if ((pi->sh->chip == BCM43224_CHIP_ID) && ++ (pi->sh->chiprev == 1)) { ++ (void)read_phy_reg(pi, tblDataLo); ++ ++ write_phy_reg(pi, tblAddr, ++ (tbl_id << 10) | (tbl_offset + idx)); ++ } ++ ++ if (tbl_width == 32) { ++ ptbl_32b[idx] = read_phy_reg(pi, tblDataLo); ++ ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16); ++ } else if (tbl_width == 16) { ++ ptbl_16b[idx] = read_phy_reg(pi, tblDataLo); ++ } else { ++ ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo); ++ } ++ } ++} ++ ++uint ++wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, ++ struct radio_20xx_regs *radioregs) ++{ ++ uint i = 0; ++ ++ do { ++ if (radioregs[i].do_init) ++ write_radio_reg(pi, radioregs[i].address, ++ (u16) radioregs[i].init); ++ ++ i++; ++ } while (radioregs[i].address != 0xffff); ++ ++ return i; ++} ++ ++uint ++wlc_phy_init_radio_regs(struct brcms_phy *pi, ++ const struct radio_regs *radioregs, ++ u16 core_offset) ++{ ++ uint i = 0; ++ uint count = 0; ++ ++ do { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (radioregs[i].do_init_a) { ++ write_radio_reg(pi, ++ radioregs[i]. ++ address | core_offset, ++ (u16) radioregs[i].init_a); ++ if (ISNPHY(pi) && (++count % 4 == 0)) ++ BRCMS_PHY_WAR_PR51571(pi); ++ } ++ } else { ++ if (radioregs[i].do_init_g) { ++ write_radio_reg(pi, ++ radioregs[i]. ++ address | core_offset, ++ (u16) radioregs[i].init_g); ++ if (ISNPHY(pi) && (++count % 4 == 0)) ++ BRCMS_PHY_WAR_PR51571(pi); ++ } ++ } ++ ++ i++; ++ } while (radioregs[i].address != 0xffff); ++ ++ return i; ++} ++ ++void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) ++{ ++#define DUMMY_PKT_LEN 20 ++ struct d11regs __iomem *regs = pi->regs; ++ int i, count; ++ u8 ofdmpkt[DUMMY_PKT_LEN] = { ++ 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 ++ }; ++ u8 cckpkt[DUMMY_PKT_LEN] = { ++ 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 ++ }; ++ u32 *dummypkt; ++ ++ dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt); ++ wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN, ++ dummypkt); ++ ++ W_REG(®s->xmtsel, 0); ++ ++ if (D11REV_GE(pi->sh->corerev, 11)) ++ W_REG(®s->wepctl, 0x100); ++ else ++ W_REG(®s->wepctl, 0); ++ ++ W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0); ++ if (ISNPHY(pi) || ISLCNPHY(pi)) ++ W_REG(®s->txe_phyctl1, 0x1A02); ++ ++ W_REG(®s->txe_wm_0, 0); ++ W_REG(®s->txe_wm_1, 0); ++ ++ W_REG(®s->xmttplatetxptr, 0); ++ W_REG(®s->xmttxcnt, DUMMY_PKT_LEN); ++ ++ W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2)); ++ ++ W_REG(®s->txe_ctl, 0); ++ ++ if (!pa_on) { ++ if (ISNPHY(pi)) ++ wlc_phy_pa_override_nphy(pi, OFF); ++ } ++ ++ if (ISNPHY(pi) || ISLCNPHY(pi)) ++ W_REG(®s->txe_aux, 0xD0); ++ else ++ W_REG(®s->txe_aux, ((1 << 5) | (1 << 4))); ++ ++ (void)R_REG(®s->txe_aux); ++ ++ i = 0; ++ count = ofdm ? 30 : 250; ++ while ((i++ < count) ++ && (R_REG(®s->txe_status) & (1 << 7))) ++ udelay(10); ++ ++ i = 0; ++ ++ while ((i++ < 10) ++ && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) ++ udelay(10); ++ ++ i = 0; ++ ++ while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8)))) ++ udelay(10); ++ ++ if (!pa_on) { ++ if (ISNPHY(pi)) ++ wlc_phy_pa_override_nphy(pi, ON); ++ } ++} ++ ++void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (set) ++ mboolset(pi->measure_hold, id); ++ else ++ mboolclr(pi->measure_hold, id); ++ ++ return; ++} ++ ++void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (mute) ++ mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE); ++ else ++ mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE); ++ ++ if (!mute && (flags & PHY_MUTE_FOR_PREISM)) ++ pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer; ++ return; ++} ++ ++void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (ISNPHY(pi)) { ++ return; ++ } else { ++ wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W); ++ } ++} ++ ++static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) ++{ ++ return false; ++} ++ ++void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ (void)R_REG(&pi->regs->maccontrol); ++ ++ if (ISNPHY(pi)) { ++ wlc_phy_switch_radio_nphy(pi, on); ++ } else if (ISLCNPHY(pi)) { ++ if (on) { ++ and_phy_reg(pi, 0x44c, ++ ~((0x1 << 8) | ++ (0x1 << 9) | ++ (0x1 << 10) | (0x1 << 11) | (0x1 << 12))); ++ and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11))); ++ and_phy_reg(pi, 0x4f9, ~(0x1 << 3)); ++ } else { ++ and_phy_reg(pi, 0x44d, ++ ~((0x1 << 10) | ++ (0x1 << 11) | ++ (0x1 << 12) | (0x1 << 13) | (0x1 << 14))); ++ or_phy_reg(pi, 0x44c, ++ (0x1 << 8) | ++ (0x1 << 9) | ++ (0x1 << 10) | (0x1 << 11) | (0x1 << 12)); ++ ++ and_phy_reg(pi, 0x4b7, ~((0x7f << 8))); ++ and_phy_reg(pi, 0x4b1, ~((0x1 << 13))); ++ or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11)); ++ and_phy_reg(pi, 0x4fa, ~((0x1 << 3))); ++ or_phy_reg(pi, 0x4f9, (0x1 << 3)); ++ } ++ } ++} ++ ++u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ return pi->bw; ++} ++ ++void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->bw = bw; ++} ++ ++void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ pi->radio_chanspec = newch; ++ ++} ++ ++u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ return pi->radio_chanspec; ++} ++ ++void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ u16 m_cur_channel; ++ void (*chanspec_set)(struct brcms_phy *, u16) = NULL; ++ m_cur_channel = CHSPEC_CHANNEL(chanspec); ++ if (CHSPEC_IS5G(chanspec)) ++ m_cur_channel |= D11_CURCHANNEL_5G; ++ if (CHSPEC_IS40(chanspec)) ++ m_cur_channel |= D11_CURCHANNEL_40; ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel); ++ ++ chanspec_set = pi->pi_fptr.chanset; ++ if (chanspec_set) ++ (*chanspec_set)(pi, chanspec); ++ ++} ++ ++int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq) ++{ ++ int range = -1; ++ ++ if (freq < 2500) ++ range = WL_CHAN_FREQ_RANGE_2G; ++ else if (freq <= 5320) ++ range = WL_CHAN_FREQ_RANGE_5GL; ++ else if (freq <= 5700) ++ range = WL_CHAN_FREQ_RANGE_5GM; ++ else ++ range = WL_CHAN_FREQ_RANGE_5GH; ++ ++ return range; ++} ++ ++int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) ++{ ++ int range = -1; ++ uint channel = CHSPEC_CHANNEL(chanspec); ++ uint freq = wlc_phy_channel2freq(channel); ++ ++ if (ISNPHY(pi)) ++ range = wlc_phy_get_chan_freq_range_nphy(pi, channel); ++ else if (ISLCNPHY(pi)) ++ range = wlc_phy_chanspec_freq2bandrange_lpssn(freq); ++ ++ return range; ++} ++ ++void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, ++ bool wide_filter) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->channel_14_wide_filter = wide_filter; ++ ++} ++ ++int wlc_phy_channel2freq(uint channel) ++{ ++ uint i; ++ ++ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) ++ if (chan_info_all[i].chan == channel) ++ return chan_info_all[i].freq; ++ return 0; ++} ++ ++void ++wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, ++ struct brcms_chanvec *channels) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ uint i; ++ uint channel; ++ ++ memset(channels, 0, sizeof(struct brcms_chanvec)); ++ ++ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { ++ channel = chan_info_all[i].chan; ++ ++ if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) ++ && (channel <= LAST_REF5_CHANNUM)) ++ continue; ++ ++ if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || ++ (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) ++ setbit(channels->vec, channel); ++ } ++} ++ ++u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ uint i; ++ uint channel; ++ u16 chspec; ++ ++ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { ++ channel = chan_info_all[i].chan; ++ ++ if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) { ++ uint j; ++ ++ for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) { ++ if (chan_info_all[j].chan == ++ channel + CH_10MHZ_APART) ++ break; ++ } ++ ++ if (j == ARRAY_SIZE(chan_info_all)) ++ continue; ++ ++ channel = upper_20_sb(channel); ++ chspec = channel | WL_CHANSPEC_BW_40 | ++ WL_CHANSPEC_CTL_SB_LOWER; ++ if (band == BRCM_BAND_2G) ++ chspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chspec |= WL_CHANSPEC_BAND_5G; ++ } else ++ chspec = ch20mhz_chspec(channel); ++ ++ if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) ++ && (channel <= LAST_REF5_CHANNUM)) ++ continue; ++ ++ if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || ++ (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) ++ return chspec; ++ } ++ ++ return (u16) INVCHANSPEC; ++} ++ ++int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ *qdbm = pi->tx_user_target[0]; ++ if (override != NULL) ++ *override = pi->txpwroverride; ++ return 0; ++} ++ ++void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, ++ struct txpwr_limits *txpwr) ++{ ++ bool mac_enabled = false; ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ memcpy(&pi->tx_user_target[TXP_FIRST_CCK], ++ &txpwr->cck[0], BRCMS_NUM_RATES_CCK); ++ ++ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM], ++ &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD], ++ &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM); ++ ++ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], ++ &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], ++ &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM); ++ ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO], ++ &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD], ++ &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC], ++ &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM], ++ &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); ++ ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO], ++ &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD], ++ &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC], ++ &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); ++ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], ++ &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); ++ ++ if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ++ mac_enabled = true; ++ ++ if (mac_enabled) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phy_txpower_recalc_target(pi); ++ wlc_phy_cal_txpower_recalc_sw(pi); ++ ++ if (mac_enabled) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ int i; ++ ++ if (qdbm > 127) ++ return -EINVAL; ++ ++ for (i = 0; i < TXP_NUM_RATES; i++) ++ pi->tx_user_target[i] = (u8) qdbm; ++ ++ pi->txpwroverride = false; ++ ++ if (pi->sh->up) { ++ if (!SCAN_INPROG_PHY(pi)) { ++ bool suspend; ++ ++ suspend = (0 == (R_REG(&pi->regs->maccontrol) & ++ MCTL_EN_MAC)); ++ ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phy_txpower_recalc_target(pi); ++ wlc_phy_cal_txpower_recalc_sw(pi); ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ } ++ } ++ return 0; ++} ++ ++void ++wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, ++ u8 *max_pwr, int txp_rate_idx) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ uint i; ++ ++ *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR; ++ ++ if (ISNPHY(pi)) { ++ if (txp_rate_idx < 0) ++ txp_rate_idx = TXP_FIRST_CCK; ++ wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr, ++ (u8) txp_rate_idx); ++ ++ } else if ((channel <= CH_MAX_2G_CHANNEL)) { ++ if (txp_rate_idx < 0) ++ txp_rate_idx = TXP_FIRST_CCK; ++ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; ++ } else { ++ ++ *max_pwr = BRCMS_TXPWR_MAX; ++ ++ if (txp_rate_idx < 0) ++ txp_rate_idx = TXP_FIRST_OFDM; ++ ++ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { ++ if (channel == chan_info_all[i].chan) ++ break; ++ } ++ ++ if (pi->hwtxpwr) { ++ *max_pwr = pi->hwtxpwr[i]; ++ } else { ++ ++ if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN)) ++ *max_pwr = ++ pi->tx_srom_max_rate_5g_mid[txp_rate_idx]; ++ if ((i >= FIRST_HIGH_5G_CHAN) ++ && (i <= LAST_HIGH_5G_CHAN)) ++ *max_pwr = ++ pi->tx_srom_max_rate_5g_hi[txp_rate_idx]; ++ if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN)) ++ *max_pwr = ++ pi->tx_srom_max_rate_5g_low[txp_rate_idx]; ++ } ++ } ++} ++ ++void ++wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, ++ u8 *max_txpwr, u8 *min_txpwr) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ u8 tx_pwr_max = 0; ++ u8 tx_pwr_min = 255; ++ u8 max_num_rate; ++ u8 maxtxpwr, mintxpwr, rate, pactrl; ++ ++ pactrl = 0; ++ ++ max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES : ++ ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + ++ 1) : (TXP_LAST_OFDM + 1); ++ ++ for (rate = 0; rate < max_num_rate; rate++) { ++ ++ wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr, ++ rate); ++ ++ maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; ++ ++ maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; ++ ++ tx_pwr_max = max(tx_pwr_max, maxtxpwr); ++ tx_pwr_min = min(tx_pwr_min, maxtxpwr); ++ } ++ *max_txpwr = tx_pwr_max; ++ *min_txpwr = tx_pwr_min; ++} ++ ++void ++wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, ++ s32 *max_pwr, s32 *min_pwr, u32 *step_pwr) ++{ ++ return; ++} ++ ++u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ return pi->tx_power_min; ++} ++ ++u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ return pi->tx_power_max; ++} ++ ++static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi) ++{ ++ if (ISLCNPHY(pi)) ++ return wlc_lcnphy_vbatsense(pi, 0); ++ else ++ return 0; ++} ++ ++static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi) ++{ ++ if (ISLCNPHY(pi)) ++ return wlc_lcnphy_tempsense_degree(pi, 0); ++ else ++ return 0; ++} ++ ++static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band) ++{ ++ u8 i; ++ s8 temp, vbat; ++ ++ for (i = 0; i < TXP_NUM_RATES; i++) ++ pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; ++ ++ vbat = wlc_phy_env_measure_vbat(pi); ++ temp = wlc_phy_env_measure_temperature(pi); ++ ++} ++ ++static s8 ++wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band, ++ u8 rate) ++{ ++ s8 offset = 0; ++ ++ if (!pi->user_txpwr_at_rfport) ++ return offset; ++ return offset; ++} ++ ++void wlc_phy_txpower_recalc_target(struct brcms_phy *pi) ++{ ++ u8 maxtxpwr, mintxpwr, rate, pactrl; ++ uint target_chan; ++ u8 tx_pwr_target[TXP_NUM_RATES]; ++ u8 tx_pwr_max = 0; ++ u8 tx_pwr_min = 255; ++ u8 tx_pwr_max_rate_ind = 0; ++ u8 max_num_rate; ++ u8 start_rate = 0; ++ u16 chspec; ++ u32 band = CHSPEC2BAND(pi->radio_chanspec); ++ void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL; ++ ++ chspec = pi->radio_chanspec; ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) ++ target_chan = CHSPEC_CHANNEL(chspec); ++ else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) ++ target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec)); ++ else ++ target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec)); ++ ++ pactrl = 0; ++ if (ISLCNPHY(pi)) { ++ u32 offset_mcs, i; ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) { ++ offset_mcs = pi->mcs40_po; ++ for (i = TXP_FIRST_SISO_MCS_20; ++ i <= TXP_LAST_SISO_MCS_20; i++) { ++ pi->tx_srom_max_rate_2g[i - 8] = ++ pi->tx_srom_max_2g - ++ ((offset_mcs & 0xf) * 2); ++ offset_mcs >>= 4; ++ } ++ } else { ++ offset_mcs = pi->mcs20_po; ++ for (i = TXP_FIRST_SISO_MCS_20; ++ i <= TXP_LAST_SISO_MCS_20; i++) { ++ pi->tx_srom_max_rate_2g[i - 8] = ++ pi->tx_srom_max_2g - ++ ((offset_mcs & 0xf) * 2); ++ offset_mcs >>= 4; ++ } ++ } ++ } ++ ++ max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : ++ ((ISLCNPHY(pi)) ? ++ (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1))); ++ ++ wlc_phy_upd_env_txpwr_rate_limits(pi, band); ++ ++ for (rate = start_rate; rate < max_num_rate; rate++) { ++ ++ tx_pwr_target[rate] = pi->tx_user_target[rate]; ++ ++ if (pi->user_txpwr_at_rfport) ++ tx_pwr_target[rate] += ++ wlc_user_txpwr_antport_to_rfport(pi, ++ target_chan, ++ band, ++ rate); ++ ++ wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi, ++ target_chan, ++ &mintxpwr, &maxtxpwr, rate); ++ ++ maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]); ++ ++ maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; ++ ++ maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; ++ ++ maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]); ++ ++ if (pi->txpwr_percent <= 100) ++ maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100; ++ ++ tx_pwr_target[rate] = max(maxtxpwr, mintxpwr); ++ ++ tx_pwr_target[rate] = ++ min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]); ++ ++ if (tx_pwr_target[rate] > tx_pwr_max) ++ tx_pwr_max_rate_ind = rate; ++ ++ tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]); ++ tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]); ++ } ++ ++ memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset)); ++ pi->tx_power_max = tx_pwr_max; ++ pi->tx_power_min = tx_pwr_min; ++ pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind; ++ for (rate = 0; rate < max_num_rate; rate++) { ++ ++ pi->tx_power_target[rate] = tx_pwr_target[rate]; ++ ++ if (!pi->hwpwrctrl || ISNPHY(pi)) ++ pi->tx_power_offset[rate] = ++ pi->tx_power_max - pi->tx_power_target[rate]; ++ else ++ pi->tx_power_offset[rate] = ++ pi->tx_power_target[rate] - pi->tx_power_min; ++ } ++ ++ txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc; ++ if (txpwr_recalc_fn) ++ (*txpwr_recalc_fn)(pi); ++} ++ ++static void ++wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, ++ u16 chanspec) ++{ ++ u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM]; ++ u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL; ++ int rate_start_index = 0, rate1, rate2, k; ++ ++ for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0; ++ rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++) ++ pi->txpwr_limit[rate1] = txpwr->cck[rate2]; ++ ++ for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0; ++ rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++) ++ pi->txpwr_limit[rate1] = txpwr->ofdm[rate2]; ++ ++ if (ISNPHY(pi)) { ++ ++ for (k = 0; k < 4; k++) { ++ switch (k) { ++ case 0: ++ ++ txpwr_ptr1 = txpwr->mcs_20_siso; ++ txpwr_ptr2 = txpwr->ofdm; ++ rate_start_index = WL_TX_POWER_OFDM_FIRST; ++ break; ++ case 1: ++ ++ txpwr_ptr1 = txpwr->mcs_20_cdd; ++ txpwr_ptr2 = txpwr->ofdm_cdd; ++ rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST; ++ break; ++ case 2: ++ ++ txpwr_ptr1 = txpwr->mcs_40_siso; ++ txpwr_ptr2 = txpwr->ofdm_40_siso; ++ rate_start_index = ++ WL_TX_POWER_OFDM40_SISO_FIRST; ++ break; ++ case 3: ++ ++ txpwr_ptr1 = txpwr->mcs_40_cdd; ++ txpwr_ptr2 = txpwr->ofdm_40_cdd; ++ rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST; ++ break; ++ } ++ ++ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; ++ rate2++) { ++ tmp_txpwr_limit[rate2] = 0; ++ tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = ++ txpwr_ptr1[rate2]; ++ } ++ wlc_phy_mcs_to_ofdm_powers_nphy( ++ tmp_txpwr_limit, 0, ++ BRCMS_NUM_RATES_OFDM - ++ 1, BRCMS_NUM_RATES_OFDM); ++ for (rate1 = rate_start_index, rate2 = 0; ++ rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++) ++ pi->txpwr_limit[rate1] = ++ min(txpwr_ptr2[rate2], ++ tmp_txpwr_limit[rate2]); ++ } ++ ++ for (k = 0; k < 4; k++) { ++ switch (k) { ++ case 0: ++ ++ txpwr_ptr1 = txpwr->ofdm; ++ txpwr_ptr2 = txpwr->mcs_20_siso; ++ rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST; ++ break; ++ case 1: ++ ++ txpwr_ptr1 = txpwr->ofdm_cdd; ++ txpwr_ptr2 = txpwr->mcs_20_cdd; ++ rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST; ++ break; ++ case 2: ++ ++ txpwr_ptr1 = txpwr->ofdm_40_siso; ++ txpwr_ptr2 = txpwr->mcs_40_siso; ++ rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST; ++ break; ++ case 3: ++ ++ txpwr_ptr1 = txpwr->ofdm_40_cdd; ++ txpwr_ptr2 = txpwr->mcs_40_cdd; ++ rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST; ++ break; ++ } ++ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; ++ rate2++) { ++ tmp_txpwr_limit[rate2] = 0; ++ tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = ++ txpwr_ptr1[rate2]; ++ } ++ wlc_phy_ofdm_to_mcs_powers_nphy( ++ tmp_txpwr_limit, 0, ++ BRCMS_NUM_RATES_OFDM - ++ 1, BRCMS_NUM_RATES_OFDM); ++ for (rate1 = rate_start_index, rate2 = 0; ++ rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; ++ rate1++, rate2++) ++ pi->txpwr_limit[rate1] = ++ min(txpwr_ptr2[rate2], ++ tmp_txpwr_limit[rate2]); ++ } ++ ++ for (k = 0; k < 2; k++) { ++ switch (k) { ++ case 0: ++ ++ rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST; ++ txpwr_ptr1 = txpwr->mcs_20_stbc; ++ break; ++ case 1: ++ ++ rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST; ++ txpwr_ptr1 = txpwr->mcs_40_stbc; ++ break; ++ } ++ for (rate1 = rate_start_index, rate2 = 0; ++ rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; ++ rate1++, rate2++) ++ pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; ++ } ++ ++ for (k = 0; k < 2; k++) { ++ switch (k) { ++ case 0: ++ ++ rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST; ++ txpwr_ptr1 = txpwr->mcs_20_mimo; ++ break; ++ case 1: ++ ++ rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST; ++ txpwr_ptr1 = txpwr->mcs_40_mimo; ++ break; ++ } ++ for (rate1 = rate_start_index, rate2 = 0; ++ rate2 < BRCMS_NUM_RATES_MCS_2_STREAM; ++ rate1++, rate2++) ++ pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; ++ } ++ ++ pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32; ++ ++ pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] = ++ min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST], ++ pi->txpwr_limit[WL_TX_POWER_MCS_32]); ++ pi->txpwr_limit[WL_TX_POWER_MCS_32] = ++ pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST]; ++ } ++} ++ ++void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->txpwr_percent = txpwr_percent; ++} ++ ++void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->sh->machwcap = machwcap; ++} ++ ++void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ u16 rxc; ++ rxc = 0; ++ ++ if (start_end == ON) { ++ if (!ISNPHY(pi)) ++ return; ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 3) ++ || NREV_IS(pi->pubpi.phy_rev, 4)) { ++ W_REG(&pi->regs->phyregaddr, 0xa0); ++ (void)R_REG(&pi->regs->phyregaddr); ++ rxc = R_REG(&pi->regs->phyregdata); ++ W_REG(&pi->regs->phyregdata, ++ (0x1 << 15) | rxc); ++ } ++ } else { ++ if (NREV_IS(pi->pubpi.phy_rev, 3) ++ || NREV_IS(pi->pubpi.phy_rev, 4)) { ++ W_REG(&pi->regs->phyregaddr, 0xa0); ++ (void)R_REG(&pi->regs->phyregaddr); ++ W_REG(&pi->regs->phyregdata, rxc); ++ } ++ ++ wlc_phy_por_inform(ppi); ++ } ++} ++ ++void ++wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, ++ u16 chanspec) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec); ++ ++ if (ISLCNPHY(pi)) { ++ int i, j; ++ for (i = TXP_FIRST_OFDM_20_CDD, j = 0; ++ j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) { ++ if (txpwr->mcs_20_siso[j]) ++ pi->txpwr_limit[i] = txpwr->mcs_20_siso[j]; ++ else ++ pi->txpwr_limit[i] = txpwr->ofdm[j]; ++ } ++ } ++ ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phy_txpower_recalc_target(pi); ++ wlc_phy_cal_txpower_recalc_sw(pi); ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->ofdm_rateset_war = war; ++} ++ ++void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->bf_preempt_4306 = bf_preempt; ++} ++ ++void wlc_phy_txpower_update_shm(struct brcms_phy *pi) ++{ ++ int j; ++ if (ISNPHY(pi)) ++ return; ++ ++ if (!pi->sh->clk) ++ return; ++ ++ if (pi->hwpwrctrl) { ++ u16 offset; ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N, ++ 1 << NUM_TSSI_FRAMES); ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET, ++ pi->tx_power_min << NUM_TSSI_FRAMES); ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR, ++ pi->hwpwr_txcur); ++ ++ for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) { ++ const u8 ucode_ofdm_rates[] = { ++ 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c ++ }; ++ offset = wlapi_bmac_rate_shm_offset( ++ pi->sh->physhim, ++ ucode_ofdm_rates[j - TXP_FIRST_OFDM]); ++ wlapi_bmac_write_shm(pi->sh->physhim, offset + 6, ++ pi->tx_power_offset[j]); ++ wlapi_bmac_write_shm(pi->sh->physhim, offset + 14, ++ -(pi->tx_power_offset[j] / 2)); ++ } ++ ++ wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL, ++ MHF2_HWPWRCTL, BRCM_BAND_ALL); ++ } else { ++ int i; ++ ++ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) ++ pi->tx_power_offset[i] = ++ (u8) roundup(pi->tx_power_offset[i], 8); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET, ++ (u16) ++ ((pi->tx_power_offset[TXP_FIRST_OFDM] ++ + 7) >> 3)); ++ } ++} ++ ++bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ if (ISNPHY(pi)) ++ return pi->nphy_txpwrctrl; ++ else ++ return pi->hwpwrctrl; ++} ++ ++void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ bool suspend; ++ ++ if (!pi->hwpwrctrl_capable) ++ return; ++ ++ pi->hwpwrctrl = hwpwrctrl; ++ pi->nphy_txpwrctrl = hwpwrctrl; ++ pi->txpwrctrl = hwpwrctrl; ++ ++ if (ISNPHY(pi)) { ++ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); ++ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) ++ wlc_phy_txpwr_fixpower_nphy(pi); ++ else ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), ++ pi->saved_txpwr_idx); ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ } ++} ++ ++void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi) ++{ ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2); ++ pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2); ++ } else { ++ pi->ipa2g_on = false; ++ pi->ipa5g_on = false; ++ } ++} ++ ++static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi) ++{ ++ s16 tx0_status, tx1_status; ++ u16 estPower1, estPower2; ++ u8 pwr0, pwr1, adj_pwr0, adj_pwr1; ++ u32 est_pwr; ++ ++ estPower1 = read_phy_reg(pi, 0x118); ++ estPower2 = read_phy_reg(pi, 0x119); ++ ++ if ((estPower1 & (0x1 << 8)) == (0x1 << 8)) ++ pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0; ++ else ++ pwr0 = 0x80; ++ ++ if ((estPower2 & (0x1 << 8)) == (0x1 << 8)) ++ pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0; ++ else ++ pwr1 = 0x80; ++ ++ tx0_status = read_phy_reg(pi, 0x1ed); ++ tx1_status = read_phy_reg(pi, 0x1ee); ++ ++ if ((tx0_status & (0x1 << 15)) == (0x1 << 15)) ++ adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0; ++ else ++ adj_pwr0 = 0x80; ++ if ((tx1_status & (0x1 << 15)) == (0x1 << 15)) ++ adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0; ++ else ++ adj_pwr1 = 0x80; ++ ++ est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | ++ adj_pwr1); ++ ++ return est_pwr; ++} ++ ++void ++wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, ++ uint channel) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ uint rate, num_rates; ++ u8 min_pwr, max_pwr; ++ ++#if WL_TX_POWER_RATES != TXP_NUM_RATES ++#error "struct tx_power out of sync with this fn" ++#endif ++ ++ if (ISNPHY(pi)) { ++ power->rf_cores = 2; ++ power->flags |= (WL_TX_POWER_F_MIMO); ++ if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON) ++ power->flags |= ++ (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW); ++ } else if (ISLCNPHY(pi)) { ++ power->rf_cores = 1; ++ power->flags |= (WL_TX_POWER_F_SISO); ++ if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF) ++ power->flags |= WL_TX_POWER_F_ENABLED; ++ if (pi->hwpwrctrl) ++ power->flags |= WL_TX_POWER_F_HW; ++ } ++ ++ num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : ++ ((ISLCNPHY(pi)) ? ++ (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1))); ++ ++ for (rate = 0; rate < num_rates; rate++) { ++ power->user_limit[rate] = pi->tx_user_target[rate]; ++ wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr, ++ rate); ++ power->board_limit[rate] = (u8) max_pwr; ++ power->target[rate] = pi->tx_power_target[rate]; ++ } ++ ++ if (ISNPHY(pi)) { ++ u32 est_pout; ++ ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_phyreg_enter((struct brcms_phy_pub *) pi); ++ est_pout = wlc_phy_txpower_est_power_nphy(pi); ++ wlc_phyreg_exit((struct brcms_phy_pub *) pi); ++ wlapi_enable_mac(pi->sh->physhim); ++ ++ power->est_Pout[0] = (est_pout >> 8) & 0xff; ++ power->est_Pout[1] = est_pout & 0xff; ++ ++ power->est_Pout_act[0] = est_pout >> 24; ++ power->est_Pout_act[1] = (est_pout >> 16) & 0xff; ++ ++ if (power->est_Pout[0] == 0x80) ++ power->est_Pout[0] = 0; ++ if (power->est_Pout[1] == 0x80) ++ power->est_Pout[1] = 0; ++ ++ if (power->est_Pout_act[0] == 0x80) ++ power->est_Pout_act[0] = 0; ++ if (power->est_Pout_act[1] == 0x80) ++ power->est_Pout_act[1] = 0; ++ ++ power->est_Pout_cck = 0; ++ ++ power->tx_power_max[0] = pi->tx_power_max; ++ power->tx_power_max[1] = pi->tx_power_max; ++ ++ power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind; ++ power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind; ++ } else if (pi->hwpwrctrl && pi->sh->up) { ++ ++ wlc_phyreg_enter(ppi); ++ if (ISLCNPHY(pi)) { ++ ++ power->tx_power_max[0] = pi->tx_power_max; ++ power->tx_power_max[1] = pi->tx_power_max; ++ ++ power->tx_power_max_rate_ind[0] = ++ pi->tx_power_max_rate_ind; ++ power->tx_power_max_rate_ind[1] = ++ pi->tx_power_max_rate_ind; ++ ++ if (wlc_phy_tpc_isenabled_lcnphy(pi)) ++ power->flags |= ++ (WL_TX_POWER_F_HW | ++ WL_TX_POWER_F_ENABLED); ++ else ++ power->flags &= ++ ~(WL_TX_POWER_F_HW | ++ WL_TX_POWER_F_ENABLED); ++ ++ wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0], ++ (s8 *) &power->est_Pout_cck); ++ } ++ wlc_phyreg_exit(ppi); ++ } ++} ++ ++void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ pi->antsel_type = antsel_type; ++} ++ ++bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ return pi->phytest_on; ++} ++ ++void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ bool suspend; ++ ++ pi->sh->rx_antdiv = val; ++ ++ if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) { ++ if (val > ANT_RX_DIV_FORCE_1) ++ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, ++ MHF1_ANTDIV, BRCM_BAND_ALL); ++ else ++ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0, ++ BRCM_BAND_ALL); ++ } ++ ++ if (ISNPHY(pi)) ++ return; ++ ++ if (!pi->sh->clk) ++ return; ++ ++ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ if (ISLCNPHY(pi)) { ++ if (val > ANT_RX_DIV_FORCE_1) { ++ mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1); ++ mod_phy_reg(pi, 0x410, ++ (0x1 << 0), ++ ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0); ++ } else { ++ mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1); ++ mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0); ++ } ++ } ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ ++ return; ++} ++ ++static bool ++wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant) ++{ ++ s8 cmplx_pwr_dbm[PHY_CORE_MAX]; ++ u8 i; ++ ++ memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm)); ++ wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum); ++ ++ for (i = 0; i < pi->pubpi.phy_corenum; i++) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322; ++ else ++ ++ cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70); ++ } ++ ++ for (i = 0; i < pi->pubpi.phy_corenum; i++) { ++ pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i]; ++ pwr_ant[i] = cmplx_pwr_dbm[i]; ++ } ++ pi->nphy_noise_index = ++ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); ++ return true; ++} ++ ++static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm) ++{ ++ if (!pi->phynoise_state) ++ return; ++ ++ if (pi->phynoise_state & PHY_NOISE_STATE_MON) { ++ if (pi->phynoise_chan_watchdog == channel) { ++ pi->sh->phy_noise_window[pi->sh->phy_noise_index] = ++ noise_dbm; ++ pi->sh->phy_noise_index = ++ MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ); ++ } ++ pi->phynoise_state &= ~PHY_NOISE_STATE_MON; ++ } ++ ++ if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) ++ pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL; ++ ++} ++ ++static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi) ++{ ++ u32 cmplx_pwr[PHY_CORE_MAX]; ++ s8 noise_dbm_ant[PHY_CORE_MAX]; ++ u16 lo, hi; ++ u32 cmplx_pwr_tot = 0; ++ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; ++ u8 idx, core; ++ ++ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); ++ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); ++ ++ for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, ++ core++) { ++ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx)); ++ hi = wlapi_bmac_read_shm(pi->sh->physhim, ++ M_PWRIND_MAP(idx + 1)); ++ cmplx_pwr[core] = (hi << 16) + lo; ++ cmplx_pwr_tot += cmplx_pwr[core]; ++ if (cmplx_pwr[core] == 0) ++ noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY; ++ else ++ cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE; ++ } ++ ++ if (cmplx_pwr_tot != 0) ++ wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ pi->nphy_noise_win[core][pi->nphy_noise_index] = ++ noise_dbm_ant[core]; ++ ++ if (noise_dbm_ant[core] > noise_dbm) ++ noise_dbm = noise_dbm_ant[core]; ++ } ++ pi->nphy_noise_index = ++ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); ++ ++ return noise_dbm; ++ ++} ++ ++void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ u16 jssi_aux; ++ u8 channel = 0; ++ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; ++ ++ if (ISLCNPHY(pi)) { ++ u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1; ++ u16 lo, hi; ++ s32 pwr_offset_dB, gain_dB; ++ u16 status_0, status_1; ++ ++ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); ++ channel = jssi_aux & D11_CURCHANNEL_MAX; ++ ++ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0); ++ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1); ++ cmplx_pwr0 = (hi << 16) + lo; ++ ++ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2); ++ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3); ++ cmplx_pwr1 = (hi << 16) + lo; ++ cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6; ++ ++ status_0 = 0x44; ++ status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0); ++ if ((cmplx_pwr > 0 && cmplx_pwr < 500) ++ && ((status_1 & 0xc000) == 0x4000)) { ++ ++ wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm, ++ pi->pubpi.phy_corenum); ++ pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF); ++ if (pwr_offset_dB > 127) ++ pwr_offset_dB -= 256; ++ ++ noise_dbm += (s8) (pwr_offset_dB - 30); ++ ++ gain_dB = (status_0 & 0x1ff); ++ noise_dbm -= (s8) (gain_dB); ++ } else { ++ noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY; ++ } ++ } else if (ISNPHY(pi)) { ++ ++ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); ++ channel = jssi_aux & D11_CURCHANNEL_MAX; ++ ++ noise_dbm = wlc_phy_noise_read_shmem(pi); ++ } ++ ++ wlc_phy_noise_cb(pi, channel, noise_dbm); ++ ++} ++ ++static void ++wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; ++ bool sampling_in_progress = (pi->phynoise_state != 0); ++ bool wait_for_intr = true; ++ ++ switch (reason) { ++ case PHY_NOISE_SAMPLE_MON: ++ pi->phynoise_chan_watchdog = ch; ++ pi->phynoise_state |= PHY_NOISE_STATE_MON; ++ break; ++ ++ case PHY_NOISE_SAMPLE_EXTERNAL: ++ pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (sampling_in_progress) ++ return; ++ ++ pi->phynoise_now = pi->sh->now; ++ ++ if (pi->phy_fixed_noise) { ++ if (ISNPHY(pi)) { ++ pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] = ++ PHY_NOISE_FIXED_VAL_NPHY; ++ pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] = ++ PHY_NOISE_FIXED_VAL_NPHY; ++ pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, ++ PHY_NOISE_WINDOW_SZ); ++ noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; ++ } else { ++ noise_dbm = PHY_NOISE_FIXED_VAL; ++ } ++ ++ wait_for_intr = false; ++ goto done; ++ } ++ ++ if (ISLCNPHY(pi)) { ++ if (!pi->phynoise_polling ++ || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { ++ wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); ++ ++ OR_REG(&pi->regs->maccommand, ++ MCMD_BG_NOISE); ++ } else { ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_deaf_mode(pi, (bool) 0); ++ noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20); ++ wlc_lcnphy_deaf_mode(pi, (bool) 1); ++ wlapi_enable_mac(pi->sh->physhim); ++ wait_for_intr = false; ++ } ++ } else if (ISNPHY(pi)) { ++ if (!pi->phynoise_polling ++ || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); ++ ++ OR_REG(&pi->regs->maccommand, ++ MCMD_BG_NOISE); ++ } else { ++ struct phy_iq_est est[PHY_CORE_MAX]; ++ u32 cmplx_pwr[PHY_CORE_MAX]; ++ s8 noise_dbm_ant[PHY_CORE_MAX]; ++ u16 log_num_samps, num_samps, classif_state = 0; ++ u8 wait_time = 32; ++ u8 wait_crs = 0; ++ u8 i; ++ ++ memset((u8 *) est, 0, sizeof(est)); ++ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); ++ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); ++ ++ log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; ++ num_samps = 1 << log_num_samps; ++ ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ classif_state = wlc_phy_classifier_nphy(pi, 0, 0); ++ wlc_phy_classifier_nphy(pi, 3, 0); ++ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time, ++ wait_crs); ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); ++ wlapi_enable_mac(pi->sh->physhim); ++ ++ for (i = 0; i < pi->pubpi.phy_corenum; i++) ++ cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >> ++ log_num_samps; ++ ++ wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); ++ ++ for (i = 0; i < pi->pubpi.phy_corenum; i++) { ++ pi->nphy_noise_win[i][pi->nphy_noise_index] = ++ noise_dbm_ant[i]; ++ ++ if (noise_dbm_ant[i] > noise_dbm) ++ noise_dbm = noise_dbm_ant[i]; ++ } ++ pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, ++ PHY_NOISE_WINDOW_SZ); ++ ++ wait_for_intr = false; ++ } ++ } ++ ++done: ++ ++ if (!wait_for_intr) ++ wlc_phy_noise_cb(pi, ch, noise_dbm); ++ ++} ++ ++void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih) ++{ ++ u8 channel; ++ ++ channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih)); ++ ++ wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel); ++} ++ ++static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = { ++ 8, ++ 8, ++ 8, ++ 8, ++ 8, ++ 8, ++ 8, ++ 9, ++ 10, ++ 8, ++ 8, ++ 7, ++ 7, ++ 1, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 1, ++ 1, ++ 0, ++ 0, ++ 0, ++ 0 ++}; ++ ++void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core) ++{ ++ u8 msb, secondmsb, i; ++ u32 tmp; ++ ++ for (i = 0; i < core; i++) { ++ secondmsb = 0; ++ tmp = cmplx_pwr[i]; ++ msb = fls(tmp); ++ if (msb) ++ secondmsb = (u8) ((tmp >> (--msb - 1)) & 1); ++ p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb); ++ } ++} ++ ++int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, ++ struct d11rxhdr *rxh) ++{ ++ int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK; ++ uint radioid = pih->radioid; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if ((pi->sh->corerev >= 11) ++ && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) { ++ rssi = BRCMS_RSSI_INVALID; ++ goto end; ++ } ++ ++ if (ISLCNPHY(pi)) { ++ u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ if (rssi > 127) ++ rssi -= 256; ++ ++ rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx]; ++ if ((rssi > -46) && (gidx > 18)) ++ rssi = rssi + 7; ++ ++ rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope; ++ ++ rssi = rssi + 2; ++ ++ } ++ ++ if (ISLCNPHY(pi)) { ++ if (rssi > 127) ++ rssi -= 256; ++ } else if (radioid == BCM2055_ID || radioid == BCM2056_ID ++ || radioid == BCM2057_ID) { ++ rssi = wlc_phy_rssi_compute_nphy(pi, rxh); ++ } ++ ++end: ++ return rssi; ++} ++ ++void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih) ++{ ++ return; ++} ++ ++void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih) ++{ ++ return; ++} ++ ++void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) ++{ ++ struct brcms_phy *pi; ++ pi = (struct brcms_phy *) ppi; ++ ++ if (ISLCNPHY(pi)) ++ wlc_lcnphy_deaf_mode(pi, true); ++ else if (ISNPHY(pi)) ++ wlc_nphy_deaf_mode(pi, true); ++} ++ ++void wlc_phy_watchdog(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ bool delay_phy_cal = false; ++ pi->sh->now++; ++ ++ if (!pi->watchdog_override) ++ return; ++ ++ if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) ++ wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi, ++ PHY_NOISE_SAMPLE_MON, ++ CHSPEC_CHANNEL(pi-> ++ radio_chanspec)); ++ ++ if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) ++ pi->phynoise_state = 0; ++ ++ if ((!pi->phycal_txpower) || ++ ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) { ++ ++ if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) ++ pi->phycal_txpower = pi->sh->now; ++ } ++ ++ if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) ++ || ASSOC_INPROG_PHY(pi))) ++ return; ++ ++ if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) { ++ ++ if ((pi->nphy_perical != PHY_PERICAL_DISABLE) && ++ (pi->nphy_perical != PHY_PERICAL_MANUAL) && ++ ((pi->sh->now - pi->nphy_perical_last) >= ++ pi->sh->glacial_timer)) ++ wlc_phy_cal_perical((struct brcms_phy_pub *) pi, ++ PHY_PERICAL_WATCHDOG); ++ ++ wlc_phy_txpwr_papd_cal_nphy(pi); ++ } ++ ++ if (ISLCNPHY(pi)) { ++ if (pi->phy_forcecal || ++ ((pi->sh->now - pi->phy_lastcal) >= ++ pi->sh->glacial_timer)) { ++ if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi))) ++ wlc_lcnphy_calib_modes( ++ pi, ++ LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); ++ if (! ++ (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) ++ || ASSOC_INPROG_PHY(pi) ++ || pi->carrier_suppr_disable ++ || pi->disable_percal)) ++ wlc_lcnphy_calib_modes(pi, ++ PHY_PERICAL_WATCHDOG); ++ } ++ } ++} ++ ++void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ uint i; ++ uint k; ++ ++ for (i = 0; i < MA_WINDOW_SZ; i++) ++ pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff); ++ if (ISLCNPHY(pi)) { ++ for (i = 0; i < MA_WINDOW_SZ; i++) ++ pi->sh->phy_noise_window[i] = ++ PHY_NOISE_FIXED_VAL_LCNPHY; ++ } ++ pi->sh->phy_noise_index = 0; ++ ++ for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) { ++ for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++) ++ pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY; ++ } ++ pi->nphy_noise_index = 0; ++} ++ ++void ++wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag) ++{ ++ *eps_imag = (epsilon >> 13); ++ if (*eps_imag > 0xfff) ++ *eps_imag -= 0x2000; ++ ++ *eps_real = (epsilon & 0x1fff); ++ if (*eps_real > 0xfff) ++ *eps_real -= 0x2000; ++} ++ ++void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi) ++{ ++ wlapi_del_timer(pi->phycal_timer); ++ ++ pi->cal_type_override = PHY_PERICAL_AUTO; ++ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE; ++ pi->mphase_txcal_cmdidx = 0; ++} ++ ++static void ++wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay) ++{ ++ ++ if ((pi->nphy_perical != PHY_PERICAL_MPHASE) && ++ (pi->nphy_perical != PHY_PERICAL_MANUAL)) ++ return; ++ ++ wlapi_del_timer(pi->phycal_timer); ++ ++ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; ++ wlapi_add_timer(pi->phycal_timer, delay, 0); ++} ++ ++void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason) ++{ ++ s16 nphy_currtemp = 0; ++ s16 delta_temp = 0; ++ bool do_periodic_cal = true; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ if (!ISNPHY(pi)) ++ return; ++ ++ if ((pi->nphy_perical == PHY_PERICAL_DISABLE) || ++ (pi->nphy_perical == PHY_PERICAL_MANUAL)) ++ return; ++ ++ switch (reason) { ++ case PHY_PERICAL_DRIVERUP: ++ break; ++ ++ case PHY_PERICAL_PHYINIT: ++ if (pi->nphy_perical == PHY_PERICAL_MPHASE) { ++ if (PHY_PERICAL_MPHASE_PENDING(pi)) ++ wlc_phy_cal_perical_mphase_reset(pi); ++ ++ wlc_phy_cal_perical_mphase_schedule( ++ pi, ++ PHY_PERICAL_INIT_DELAY); ++ } ++ break; ++ ++ case PHY_PERICAL_JOIN_BSS: ++ case PHY_PERICAL_START_IBSS: ++ case PHY_PERICAL_UP_BSS: ++ if ((pi->nphy_perical == PHY_PERICAL_MPHASE) && ++ PHY_PERICAL_MPHASE_PENDING(pi)) ++ wlc_phy_cal_perical_mphase_reset(pi); ++ ++ pi->first_cal_after_assoc = true; ++ ++ pi->cal_type_override = PHY_PERICAL_FULL; ++ ++ if (pi->phycal_tempdelta) ++ pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi); ++ ++ wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL); ++ break; ++ ++ case PHY_PERICAL_WATCHDOG: ++ if (pi->phycal_tempdelta) { ++ nphy_currtemp = wlc_phy_tempsense_nphy(pi); ++ delta_temp = ++ (nphy_currtemp > pi->nphy_lastcal_temp) ? ++ nphy_currtemp - pi->nphy_lastcal_temp : ++ pi->nphy_lastcal_temp - nphy_currtemp; ++ ++ if ((delta_temp < (s16) pi->phycal_tempdelta) && ++ (pi->nphy_txiqlocal_chanspec == ++ pi->radio_chanspec)) ++ do_periodic_cal = false; ++ else ++ pi->nphy_lastcal_temp = nphy_currtemp; ++ } ++ ++ if (do_periodic_cal) { ++ if (pi->nphy_perical == PHY_PERICAL_MPHASE) { ++ if (!PHY_PERICAL_MPHASE_PENDING(pi)) ++ wlc_phy_cal_perical_mphase_schedule( ++ pi, ++ PHY_PERICAL_WDOG_DELAY); ++ } else if (pi->nphy_perical == PHY_PERICAL_SPHASE) ++ wlc_phy_cal_perical_nphy_run(pi, ++ PHY_PERICAL_AUTO); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi) ++{ ++ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; ++ pi->mphase_txcal_cmdidx = 0; ++} ++ ++u8 wlc_phy_nbits(s32 value) ++{ ++ s32 abs_val; ++ u8 nbits = 0; ++ ++ abs_val = abs(value); ++ while ((abs_val >> nbits) > 0) ++ nbits++; ++ ++ return nbits; ++} ++ ++void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->sh->hw_phytxchain = txchain; ++ pi->sh->hw_phyrxchain = rxchain; ++ pi->sh->phytxchain = txchain; ++ pi->sh->phyrxchain = rxchain; ++ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); ++} ++ ++void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ pi->sh->phytxchain = txchain; ++ ++ if (ISNPHY(pi)) ++ wlc_phy_rxcore_setstate_nphy(pih, rxchain); ++ ++ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); ++} ++ ++void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ *txchain = pi->sh->phytxchain; ++ *rxchain = pi->sh->phyrxchain; ++} ++ ++u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) ++{ ++ s16 nphy_currtemp; ++ u8 active_bitmap; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33; ++ ++ if (!pi->watchdog_override) ++ return active_bitmap; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ nphy_currtemp = wlc_phy_tempsense_nphy(pi); ++ wlapi_enable_mac(pi->sh->physhim); ++ ++ if (!pi->phy_txcore_heatedup) { ++ if (nphy_currtemp >= pi->phy_txcore_disable_temp) { ++ active_bitmap &= 0xFD; ++ pi->phy_txcore_heatedup = true; ++ } ++ } else { ++ if (nphy_currtemp <= pi->phy_txcore_enable_temp) { ++ active_bitmap |= 0x2; ++ pi->phy_txcore_heatedup = false; ++ } ++ } ++ } ++ ++ return active_bitmap; ++} ++ ++s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ u8 siso_mcs_id, cdd_mcs_id; ++ ++ siso_mcs_id = ++ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO : ++ TXP_FIRST_MCS_20_SISO; ++ cdd_mcs_id = ++ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD : ++ TXP_FIRST_MCS_20_CDD; ++ ++ if (pi->tx_power_target[siso_mcs_id] > ++ (pi->tx_power_target[cdd_mcs_id] + 12)) ++ return PHY_TXC1_MODE_SISO; ++ else ++ return PHY_TXC1_MODE_CDD; ++} ++ ++const u8 *wlc_phy_get_ofdm_rate_lookup(void) ++{ ++ return ofdm_rate_lookup; ++} ++ ++void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) ++{ ++ if ((pi->sh->chip == BCM4313_CHIP_ID) && ++ (pi->sh->boardflags & BFL_FEM)) { ++ if (mode) { ++ u16 txant = 0; ++ txant = wlapi_bmac_get_txant(pi->sh->physhim); ++ if (txant == 1) { ++ mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); ++ ++ } ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpiocontrol), ++ ~0x0, 0x0); ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpioout), 0x40, ++ 0x40); ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpioouten), 0x40, ++ 0x40); ++ } else { ++ mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); ++ ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpioout), 0x40, ++ 0x00); ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpioouten), 0x40, ++ 0x0); ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, gpiocontrol), ++ ~0x0, 0x40); ++ } ++ } ++} ++ ++void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc) ++{ ++ return; ++} ++ ++void ++wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset) ++{ ++ *cckoffset = 0; ++ *ofdmoffset = 0; ++} ++ ++s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) ++{ ++ ++ return rssi; ++} ++ ++bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ if (ISNPHY(pi)) ++ return wlc_phy_n_txpower_ipa_ison(pi); ++ else ++ return 0; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h.orig 2011-11-09 13:46:58.254800521 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h 2011-11-09 13:47:17.008566067 -0500 +@@ -0,0 +1,301 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/* ++ * phy_hal.h: functionality exported from the phy to higher layers ++ */ ++ ++#ifndef _BRCM_PHY_HAL_H_ ++#define _BRCM_PHY_HAL_H_ ++ ++#include ++#include ++#include ++ ++#define IDCODE_VER_MASK 0x0000000f ++#define IDCODE_VER_SHIFT 0 ++#define IDCODE_MFG_MASK 0x00000fff ++#define IDCODE_MFG_SHIFT 0 ++#define IDCODE_ID_MASK 0x0ffff000 ++#define IDCODE_ID_SHIFT 12 ++#define IDCODE_REV_MASK 0xf0000000 ++#define IDCODE_REV_SHIFT 28 ++ ++#define NORADIO_ID 0xe4f5 ++#define NORADIO_IDCODE 0x4e4f5246 ++ ++#define BCM2055_ID 0x2055 ++#define BCM2055_IDCODE 0x02055000 ++#define BCM2055A0_IDCODE 0x1205517f ++ ++#define BCM2056_ID 0x2056 ++#define BCM2056_IDCODE 0x02056000 ++#define BCM2056A0_IDCODE 0x1205617f ++ ++#define BCM2057_ID 0x2057 ++#define BCM2057_IDCODE 0x02057000 ++#define BCM2057A0_IDCODE 0x1205717f ++ ++#define BCM2064_ID 0x2064 ++#define BCM2064_IDCODE 0x02064000 ++#define BCM2064A0_IDCODE 0x0206417f ++ ++#define PHY_TPC_HW_OFF false ++#define PHY_TPC_HW_ON true ++ ++#define PHY_PERICAL_DRIVERUP 1 ++#define PHY_PERICAL_WATCHDOG 2 ++#define PHY_PERICAL_PHYINIT 3 ++#define PHY_PERICAL_JOIN_BSS 4 ++#define PHY_PERICAL_START_IBSS 5 ++#define PHY_PERICAL_UP_BSS 6 ++#define PHY_PERICAL_CHAN 7 ++#define PHY_FULLCAL 8 ++ ++#define PHY_PERICAL_DISABLE 0 ++#define PHY_PERICAL_SPHASE 1 ++#define PHY_PERICAL_MPHASE 2 ++#define PHY_PERICAL_MANUAL 3 ++ ++#define PHY_HOLD_FOR_ASSOC 1 ++#define PHY_HOLD_FOR_SCAN 2 ++#define PHY_HOLD_FOR_RM 4 ++#define PHY_HOLD_FOR_PLT 8 ++#define PHY_HOLD_FOR_MUTE 16 ++#define PHY_HOLD_FOR_NOT_ASSOC 0x20 ++ ++#define PHY_MUTE_FOR_PREISM 1 ++#define PHY_MUTE_ALL 0xffffffff ++ ++#define PHY_NOISE_FIXED_VAL (-95) ++#define PHY_NOISE_FIXED_VAL_NPHY (-92) ++#define PHY_NOISE_FIXED_VAL_LCNPHY (-92) ++ ++#define PHY_MODE_CAL 0x0002 ++#define PHY_MODE_NOISEM 0x0004 ++ ++#define BRCMS_TXPWR_DB_FACTOR 4 ++ ++/* a large TX Power as an init value to factor out of min() calculations, ++ * keep low enough to fit in an s8, units are .25 dBm ++ */ ++#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ ++ ++#define BRCMS_NUM_RATES_CCK 4 ++#define BRCMS_NUM_RATES_OFDM 8 ++#define BRCMS_NUM_RATES_MCS_1_STREAM 8 ++#define BRCMS_NUM_RATES_MCS_2_STREAM 8 ++#define BRCMS_NUM_RATES_MCS_3_STREAM 8 ++#define BRCMS_NUM_RATES_MCS_4_STREAM 8 ++ ++#define BRCMS_RSSI_INVALID 0 /* invalid RSSI value */ ++ ++struct d11regs; ++struct phy_shim_info; ++ ++struct txpwr_limits { ++ u8 cck[BRCMS_NUM_RATES_CCK]; ++ u8 ofdm[BRCMS_NUM_RATES_OFDM]; ++ ++ u8 ofdm_cdd[BRCMS_NUM_RATES_OFDM]; ++ ++ u8 ofdm_40_siso[BRCMS_NUM_RATES_OFDM]; ++ u8 ofdm_40_cdd[BRCMS_NUM_RATES_OFDM]; ++ ++ u8 mcs_20_siso[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_20_cdd[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_20_stbc[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_20_mimo[BRCMS_NUM_RATES_MCS_2_STREAM]; ++ ++ u8 mcs_40_siso[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_40_cdd[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_40_stbc[BRCMS_NUM_RATES_MCS_1_STREAM]; ++ u8 mcs_40_mimo[BRCMS_NUM_RATES_MCS_2_STREAM]; ++ u8 mcs32; ++}; ++ ++struct tx_power { ++ u32 flags; ++ u16 chanspec; /* txpwr report for this channel */ ++ u16 local_chanspec; /* channel on which we are associated */ ++ u8 local_max; /* local max according to the AP */ ++ u8 local_constraint; /* local constraint according to the AP */ ++ s8 antgain[2]; /* Ant gain for each band - from SROM */ ++ u8 rf_cores; /* count of RF Cores being reported */ ++ u8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ ++ u8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain ++ * without adjustment */ ++ u8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ u8 tx_power_max[4]; /* Maximum target power among all rates */ ++ /* Index of the rate with the max target power */ ++ u8 tx_power_max_rate_ind[4]; ++ /* User limit */ ++ u8 user_limit[WL_TX_POWER_RATES]; ++ /* Regulatory power limit */ ++ u8 reg_limit[WL_TX_POWER_RATES]; ++ /* Max power board can support (SROM) */ ++ u8 board_limit[WL_TX_POWER_RATES]; ++ /* Latest target power */ ++ u8 target[WL_TX_POWER_RATES]; ++}; ++ ++struct tx_inst_power { ++ u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ ++ u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ ++}; ++ ++struct brcms_chanvec { ++ u8 vec[MAXCHANNEL / NBBY]; ++}; ++ ++struct shared_phy_params { ++ struct si_pub *sih; ++ struct phy_shim_info *physhim; ++ uint unit; ++ uint corerev; ++ uint buscorerev; ++ u16 vid; ++ u16 did; ++ uint chip; ++ uint chiprev; ++ uint chippkg; ++ uint sromrev; ++ uint boardtype; ++ uint boardrev; ++ uint boardvendor; ++ u32 boardflags; ++ u32 boardflags2; ++}; ++ ++ ++extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp); ++extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, ++ struct d11regs __iomem *regs, ++ int bandtype, struct wiphy *wiphy); ++extern void wlc_phy_detach(struct brcms_phy_pub *ppi); ++ ++extern bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, ++ u16 *phyrev, u16 *radioid, ++ u16 *radiover); ++extern bool wlc_phy_get_encore(struct brcms_phy_pub *pih); ++extern u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih); ++ ++extern void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate); ++extern void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate); ++extern void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec); ++extern void wlc_phy_watchdog(struct brcms_phy_pub *ppi); ++extern int wlc_phy_down(struct brcms_phy_pub *ppi); ++extern u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih); ++extern void wlc_phy_cal_init(struct brcms_phy_pub *ppi); ++extern void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); ++ ++extern void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, ++ u16 chanspec); ++extern u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); ++extern void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, ++ u16 newch); ++extern u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); ++extern void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); ++ ++extern int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, ++ struct d11rxhdr *rxh); ++extern void wlc_phy_por_inform(struct brcms_phy_pub *ppi); ++extern void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); ++extern bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); ++ ++extern void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); ++ ++extern void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); ++extern void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); ++ ++ ++extern void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); ++ ++extern void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, ++ bool wide_filter); ++extern void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, ++ struct brcms_chanvec *channels); ++extern u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, ++ uint band); ++ ++extern void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, ++ u8 *_min_, u8 *_max_, int rate); ++extern void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, ++ uint chan, u8 *_max_, u8 *_min_); ++extern void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, ++ uint band, s32 *, s32 *, u32 *); ++extern void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, ++ struct txpwr_limits *, ++ u16 chanspec); ++extern int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, ++ bool *override); ++extern int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, ++ bool override); ++extern void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, ++ struct txpwr_limits *); ++extern bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); ++extern void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, ++ bool hwpwrctrl); ++extern u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); ++extern u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); ++extern bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); ++ ++extern void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, ++ u8 rxchain); ++extern void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, ++ u8 rxchain); ++extern void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, ++ u8 *rxchain); ++extern u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); ++extern s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, ++ u16 chanspec); ++extern void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); ++ ++extern void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); ++extern void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); ++extern void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); ++extern void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); ++ ++extern void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); ++extern void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); ++extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); ++extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); ++ ++extern void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type); ++ ++extern void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, ++ struct tx_power *power, uint channel); ++ ++extern void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); ++extern bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); ++extern void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, ++ u8 txpwr_percent); ++extern void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); ++extern void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, ++ bool bf_preempt); ++extern void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); ++ ++extern void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); ++ ++extern void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); ++extern void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); ++ ++extern const u8 *wlc_phy_get_ofdm_rate_lookup(void); ++ ++extern s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, ++ u8 mcs_offset); ++extern s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset); ++#endif /* _BRCM_PHY_HAL_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h.orig 2011-11-09 13:46:58.255800509 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h 2011-11-09 13:47:17.009566054 -0500 +@@ -0,0 +1,1169 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_PHY_INT_H_ ++#define _BRCM_PHY_INT_H_ ++ ++#include ++#include ++#include ++ ++#define PHY_VERSION { 1, 82, 8, 0 } ++ ++#define LCNXN_BASEREV 16 ++ ++struct phy_shim_info; ++ ++struct brcms_phy_srom_fem { ++ /* TSSI positive slope, 1: positive, 0: negative */ ++ u8 tssipos; ++ /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ ++ u8 extpagain; ++ /* support 32 combinations of different Pdet dynamic ranges */ ++ u8 pdetrange; ++ /* TR switch isolation */ ++ u8 triso; ++ /* antswctrl lookup table configuration: 32 possible choices */ ++ u8 antswctrllut; ++}; ++ ++#define ISNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_N) ++#define ISLCNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_LCN) ++ ++#define PHY_GET_RFATTN(rfgain) ((rfgain) & 0x0f) ++#define PHY_GET_PADMIX(rfgain) (((rfgain) & 0x10) >> 4) ++#define PHY_GET_RFGAINID(rfattn, padmix, width) ((rfattn) + ((padmix)*(width))) ++#define PHY_SAT(x, n) ((x) > ((1<<((n)-1))-1) ? ((1<<((n)-1))-1) : \ ++ ((x) < -(1<<((n)-1)) ? -(1<<((n)-1)) : (x))) ++#define PHY_SHIFT_ROUND(x, n) ((x) >= 0 ? ((x)+(1<<((n)-1)))>>(n) : (x)>>(n)) ++#define PHY_HW_ROUND(x, s) ((x >> s) + ((x >> (s-1)) & (s != 0))) ++ ++#define CH_5G_GROUP 3 ++#define A_LOW_CHANS 0 ++#define A_MID_CHANS 1 ++#define A_HIGH_CHANS 2 ++#define CH_2G_GROUP 1 ++#define G_ALL_CHANS 0 ++ ++#define FIRST_REF5_CHANNUM 149 ++#define LAST_REF5_CHANNUM 165 ++#define FIRST_5G_CHAN 14 ++#define LAST_5G_CHAN 50 ++#define FIRST_MID_5G_CHAN 14 ++#define LAST_MID_5G_CHAN 35 ++#define FIRST_HIGH_5G_CHAN 36 ++#define LAST_HIGH_5G_CHAN 41 ++#define FIRST_LOW_5G_CHAN 42 ++#define LAST_LOW_5G_CHAN 50 ++ ++#define BASE_LOW_5G_CHAN 4900 ++#define BASE_MID_5G_CHAN 5100 ++#define BASE_HIGH_5G_CHAN 5500 ++ ++#define CHAN5G_FREQ(chan) (5000 + chan*5) ++#define CHAN2G_FREQ(chan) (2407 + chan*5) ++ ++#define TXP_FIRST_CCK 0 ++#define TXP_LAST_CCK 3 ++#define TXP_FIRST_OFDM 4 ++#define TXP_LAST_OFDM 11 ++#define TXP_FIRST_OFDM_20_CDD 12 ++#define TXP_LAST_OFDM_20_CDD 19 ++#define TXP_FIRST_MCS_20_SISO 20 ++#define TXP_LAST_MCS_20_SISO 27 ++#define TXP_FIRST_MCS_20_CDD 28 ++#define TXP_LAST_MCS_20_CDD 35 ++#define TXP_FIRST_MCS_20_STBC 36 ++#define TXP_LAST_MCS_20_STBC 43 ++#define TXP_FIRST_MCS_20_SDM 44 ++#define TXP_LAST_MCS_20_SDM 51 ++#define TXP_FIRST_OFDM_40_SISO 52 ++#define TXP_LAST_OFDM_40_SISO 59 ++#define TXP_FIRST_OFDM_40_CDD 60 ++#define TXP_LAST_OFDM_40_CDD 67 ++#define TXP_FIRST_MCS_40_SISO 68 ++#define TXP_LAST_MCS_40_SISO 75 ++#define TXP_FIRST_MCS_40_CDD 76 ++#define TXP_LAST_MCS_40_CDD 83 ++#define TXP_FIRST_MCS_40_STBC 84 ++#define TXP_LAST_MCS_40_STBC 91 ++#define TXP_FIRST_MCS_40_SDM 92 ++#define TXP_LAST_MCS_40_SDM 99 ++#define TXP_MCS_32 100 ++#define TXP_NUM_RATES 101 ++#define ADJ_PWR_TBL_LEN 84 ++ ++#define TXP_FIRST_SISO_MCS_20 20 ++#define TXP_LAST_SISO_MCS_20 27 ++ ++#define PHY_CORE_NUM_1 1 ++#define PHY_CORE_NUM_2 2 ++#define PHY_CORE_NUM_3 3 ++#define PHY_CORE_NUM_4 4 ++#define PHY_CORE_MAX PHY_CORE_NUM_4 ++#define PHY_CORE_0 0 ++#define PHY_CORE_1 1 ++#define PHY_CORE_2 2 ++#define PHY_CORE_3 3 ++ ++#define MA_WINDOW_SZ 8 ++ ++#define PHY_NOISE_SAMPLE_MON 1 ++#define PHY_NOISE_SAMPLE_EXTERNAL 2 ++#define PHY_NOISE_WINDOW_SZ 16 ++#define PHY_NOISE_GLITCH_INIT_MA 10 ++#define PHY_NOISE_GLITCH_INIT_MA_BADPlCP 10 ++#define PHY_NOISE_STATE_MON 0x1 ++#define PHY_NOISE_STATE_EXTERNAL 0x2 ++#define PHY_NOISE_SAMPLE_LOG_NUM_NPHY 10 ++#define PHY_NOISE_SAMPLE_LOG_NUM_UCODE 9 ++ ++#define PHY_NOISE_OFFSETFACT_4322 (-103) ++#define PHY_NOISE_MA_WINDOW_SZ 2 ++ ++#define PHY_RSSI_TABLE_SIZE 64 ++#define RSSI_ANT_MERGE_MAX 0 ++#define RSSI_ANT_MERGE_MIN 1 ++#define RSSI_ANT_MERGE_AVG 2 ++ ++#define PHY_TSSI_TABLE_SIZE 64 ++#define APHY_TSSI_TABLE_SIZE 256 ++#define TX_GAIN_TABLE_LENGTH 64 ++#define DEFAULT_11A_TXP_IDX 24 ++#define NUM_TSSI_FRAMES 4 ++#define NULL_TSSI 0x7f ++#define NULL_TSSI_W 0x7f7f ++ ++#define PHY_PAPD_EPS_TBL_SIZE_LCNPHY 64 ++ ++#define LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL 9 ++ ++#define PHY_TXPWR_MIN 10 ++#define PHY_TXPWR_MIN_NPHY 8 ++#define RADIOPWR_OVERRIDE_DEF (-1) ++ ++#define PWRTBL_NUM_COEFF 3 ++ ++#define SPURAVOID_DISABLE 0 ++#define SPURAVOID_AUTO 1 ++#define SPURAVOID_FORCEON 2 ++#define SPURAVOID_FORCEON2 3 ++ ++#define PHY_SW_TIMER_FAST 15 ++#define PHY_SW_TIMER_SLOW 60 ++#define PHY_SW_TIMER_GLACIAL 120 ++ ++#define PHY_PERICAL_AUTO 0 ++#define PHY_PERICAL_FULL 1 ++#define PHY_PERICAL_PARTIAL 2 ++ ++#define PHY_PERICAL_NODELAY 0 ++#define PHY_PERICAL_INIT_DELAY 5 ++#define PHY_PERICAL_ASSOC_DELAY 5 ++#define PHY_PERICAL_WDOG_DELAY 5 ++ ++#define MPHASE_TXCAL_NUMCMDS 2 ++ ++#define PHY_PERICAL_MPHASE_PENDING(pi) \ ++ (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_IDLE) ++ ++enum { ++ MPHASE_CAL_STATE_IDLE = 0, ++ MPHASE_CAL_STATE_INIT = 1, ++ MPHASE_CAL_STATE_TXPHASE0, ++ MPHASE_CAL_STATE_TXPHASE1, ++ MPHASE_CAL_STATE_TXPHASE2, ++ MPHASE_CAL_STATE_TXPHASE3, ++ MPHASE_CAL_STATE_TXPHASE4, ++ MPHASE_CAL_STATE_TXPHASE5, ++ MPHASE_CAL_STATE_PAPDCAL, ++ MPHASE_CAL_STATE_RXCAL, ++ MPHASE_CAL_STATE_RSSICAL, ++ MPHASE_CAL_STATE_IDLETSSI ++}; ++ ++enum phy_cal_mode { ++ CAL_FULL, ++ CAL_RECAL, ++ CAL_CURRECAL, ++ CAL_DIGCAL, ++ CAL_GCTRL, ++ CAL_SOFT, ++ CAL_DIGLO ++}; ++ ++#define RDR_NTIERS 1 ++#define RDR_TIER_SIZE 64 ++#define RDR_LIST_SIZE (512/3) ++#define RDR_EPOCH_SIZE 40 ++#define RDR_NANTENNAS 2 ++#define RDR_NTIER_SIZE RDR_LIST_SIZE ++#define RDR_LP_BUFFER_SIZE 64 ++#define LP_LEN_HIS_SIZE 10 ++ ++#define STATIC_NUM_RF 32 ++#define STATIC_NUM_BB 9 ++ ++#define BB_MULT_MASK 0x0000ffff ++#define BB_MULT_VALID_MASK 0x80000000 ++ ++#define CORDIC_AG 39797 ++#define CORDIC_NI 18 ++#define FIXED(X) ((s32)((X) << 16)) ++ ++#define FLOAT(X) \ ++ (((X) >= 0) ? ((((X) >> 15) + 1) >> 1) : -((((-(X)) >> 15) + 1) >> 1)) ++ ++#define PHY_CHAIN_TX_DISABLE_TEMP 115 ++#define PHY_HYSTERESIS_DELTATEMP 5 ++ ++#define SCAN_INPROG_PHY(pi) \ ++ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN)) ++ ++#define PLT_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_PLT)) ++ ++#define ASSOC_INPROG_PHY(pi) \ ++ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_ASSOC)) ++ ++#define SCAN_RM_IN_PROGRESS(pi) \ ++ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN | PHY_HOLD_FOR_RM)) ++ ++#define PHY_MUTED(pi) \ ++ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_MUTE)) ++ ++#define PUB_NOT_ASSOC(pi) \ ++ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_NOT_ASSOC)) ++ ++struct phy_table_info { ++ uint table; ++ int q; ++ uint max; ++}; ++ ++struct phytbl_info { ++ const void *tbl_ptr; ++ u32 tbl_len; ++ u32 tbl_id; ++ u32 tbl_offset; ++ u32 tbl_width; ++}; ++ ++struct interference_info { ++ u8 curr_home_channel; ++ u16 crsminpwrthld_40_stored; ++ u16 crsminpwrthld_20L_stored; ++ u16 crsminpwrthld_20U_stored; ++ u16 init_gain_code_core1_stored; ++ u16 init_gain_code_core2_stored; ++ u16 init_gain_codeb_core1_stored; ++ u16 init_gain_codeb_core2_stored; ++ u16 init_gain_table_stored[4]; ++ ++ u16 clip1_hi_gain_code_core1_stored; ++ u16 clip1_hi_gain_code_core2_stored; ++ u16 clip1_hi_gain_codeb_core1_stored; ++ u16 clip1_hi_gain_codeb_core2_stored; ++ u16 nb_clip_thresh_core1_stored; ++ u16 nb_clip_thresh_core2_stored; ++ u16 init_ofdmlna2gainchange_stored[4]; ++ u16 init_ccklna2gainchange_stored[4]; ++ u16 clip1_lo_gain_code_core1_stored; ++ u16 clip1_lo_gain_code_core2_stored; ++ u16 clip1_lo_gain_codeb_core1_stored; ++ u16 clip1_lo_gain_codeb_core2_stored; ++ u16 w1_clip_thresh_core1_stored; ++ u16 w1_clip_thresh_core2_stored; ++ u16 radio_2056_core1_rssi_gain_stored; ++ u16 radio_2056_core2_rssi_gain_stored; ++ u16 energy_drop_timeout_len_stored; ++ ++ u16 ed_crs40_assertthld0_stored; ++ u16 ed_crs40_assertthld1_stored; ++ u16 ed_crs40_deassertthld0_stored; ++ u16 ed_crs40_deassertthld1_stored; ++ u16 ed_crs20L_assertthld0_stored; ++ u16 ed_crs20L_assertthld1_stored; ++ u16 ed_crs20L_deassertthld0_stored; ++ u16 ed_crs20L_deassertthld1_stored; ++ u16 ed_crs20U_assertthld0_stored; ++ u16 ed_crs20U_assertthld1_stored; ++ u16 ed_crs20U_deassertthld0_stored; ++ u16 ed_crs20U_deassertthld1_stored; ++ ++ u16 badplcp_ma; ++ u16 badplcp_ma_previous; ++ u16 badplcp_ma_total; ++ u16 badplcp_ma_list[MA_WINDOW_SZ]; ++ int badplcp_ma_index; ++ s16 pre_badplcp_cnt; ++ s16 bphy_pre_badplcp_cnt; ++ ++ u16 init_gain_core1; ++ u16 init_gain_core2; ++ u16 init_gainb_core1; ++ u16 init_gainb_core2; ++ u16 init_gain_rfseq[4]; ++ ++ u16 crsminpwr0; ++ u16 crsminpwrl0; ++ u16 crsminpwru0; ++ ++ s16 crsminpwr_index; ++ ++ u16 radio_2057_core1_rssi_wb1a_gc_stored; ++ u16 radio_2057_core2_rssi_wb1a_gc_stored; ++ u16 radio_2057_core1_rssi_wb1g_gc_stored; ++ u16 radio_2057_core2_rssi_wb1g_gc_stored; ++ u16 radio_2057_core1_rssi_wb2_gc_stored; ++ u16 radio_2057_core2_rssi_wb2_gc_stored; ++ u16 radio_2057_core1_rssi_nb_gc_stored; ++ u16 radio_2057_core2_rssi_nb_gc_stored; ++}; ++ ++struct aci_save_gphy { ++ u16 rc_cal_ovr; ++ u16 phycrsth1; ++ u16 phycrsth2; ++ u16 init_n1p1_gain; ++ u16 p1_p2_gain; ++ u16 n1_n2_gain; ++ u16 n1_p1_gain; ++ u16 div_search_gain; ++ u16 div_p1_p2_gain; ++ u16 div_search_gn_change; ++ u16 table_7_2; ++ u16 table_7_3; ++ u16 cckshbits_gnref; ++ u16 clip_thresh; ++ u16 clip2_thresh; ++ u16 clip3_thresh; ++ u16 clip_p2_thresh; ++ u16 clip_pwdn_thresh; ++ u16 clip_n1p1_thresh; ++ u16 clip_n1_pwdn_thresh; ++ u16 bbconfig; ++ u16 cthr_sthr_shdin; ++ u16 energy; ++ u16 clip_p1_p2_thresh; ++ u16 threshold; ++ u16 reg15; ++ u16 reg16; ++ u16 reg17; ++ u16 div_srch_idx; ++ u16 div_srch_p1_p2; ++ u16 div_srch_gn_back; ++ u16 ant_dwell; ++ u16 ant_wr_settle; ++}; ++ ++struct lo_complex_abgphy_info { ++ s8 i; ++ s8 q; ++}; ++ ++struct nphy_iq_comp { ++ s16 a0; ++ s16 b0; ++ s16 a1; ++ s16 b1; ++}; ++ ++struct nphy_txpwrindex { ++ s8 index; ++ s8 index_internal; ++ s8 index_internal_save; ++ u16 AfectrlOverride; ++ u16 AfeCtrlDacGain; ++ u16 rad_gain; ++ u8 bbmult; ++ u16 iqcomp_a; ++ u16 iqcomp_b; ++ u16 locomp; ++}; ++ ++struct txiqcal_cache { ++ ++ u16 txcal_coeffs_2G[8]; ++ u16 txcal_radio_regs_2G[8]; ++ struct nphy_iq_comp rxcal_coeffs_2G; ++ ++ u16 txcal_coeffs_5G[8]; ++ u16 txcal_radio_regs_5G[8]; ++ struct nphy_iq_comp rxcal_coeffs_5G; ++}; ++ ++struct nphy_pwrctrl { ++ s8 max_pwr_2g; ++ s8 idle_targ_2g; ++ s16 pwrdet_2g_a1; ++ s16 pwrdet_2g_b0; ++ s16 pwrdet_2g_b1; ++ s8 max_pwr_5gm; ++ s8 idle_targ_5gm; ++ s8 max_pwr_5gh; ++ s8 max_pwr_5gl; ++ s16 pwrdet_5gm_a1; ++ s16 pwrdet_5gm_b0; ++ s16 pwrdet_5gm_b1; ++ s16 pwrdet_5gl_a1; ++ s16 pwrdet_5gl_b0; ++ s16 pwrdet_5gl_b1; ++ s16 pwrdet_5gh_a1; ++ s16 pwrdet_5gh_b0; ++ s16 pwrdet_5gh_b1; ++ s8 idle_targ_5gl; ++ s8 idle_targ_5gh; ++ s8 idle_tssi_2g; ++ s8 idle_tssi_5g; ++ s8 idle_tssi; ++ s16 a1; ++ s16 b0; ++ s16 b1; ++}; ++ ++struct nphy_txgains { ++ u16 txlpf[2]; ++ u16 txgm[2]; ++ u16 pga[2]; ++ u16 pad[2]; ++ u16 ipa[2]; ++}; ++ ++#define PHY_NOISEVAR_BUFSIZE 10 ++ ++struct nphy_noisevar_buf { ++ int bufcount; ++ int tone_id[PHY_NOISEVAR_BUFSIZE]; ++ u32 noise_vars[PHY_NOISEVAR_BUFSIZE]; ++ u32 min_noise_vars[PHY_NOISEVAR_BUFSIZE]; ++}; ++ ++struct rssical_cache { ++ u16 rssical_radio_regs_2G[2]; ++ u16 rssical_phyregs_2G[12]; ++ ++ u16 rssical_radio_regs_5G[2]; ++ u16 rssical_phyregs_5G[12]; ++}; ++ ++struct lcnphy_cal_results { ++ ++ u16 txiqlocal_a; ++ u16 txiqlocal_b; ++ u16 txiqlocal_didq; ++ u8 txiqlocal_ei0; ++ u8 txiqlocal_eq0; ++ u8 txiqlocal_fi0; ++ u8 txiqlocal_fq0; ++ ++ u16 txiqlocal_bestcoeffs[11]; ++ u16 txiqlocal_bestcoeffs_valid; ++ ++ u32 papd_eps_tbl[PHY_PAPD_EPS_TBL_SIZE_LCNPHY]; ++ u16 analog_gain_ref; ++ u16 lut_begin; ++ u16 lut_end; ++ u16 lut_step; ++ u16 rxcompdbm; ++ u16 papdctrl; ++ u16 sslpnCalibClkEnCtrl; ++ ++ u16 rxiqcal_coeff_a0; ++ u16 rxiqcal_coeff_b0; ++}; ++ ++struct shared_phy { ++ struct brcms_phy *phy_head; ++ uint unit; ++ struct si_pub *sih; ++ struct phy_shim_info *physhim; ++ uint corerev; ++ u32 machwcap; ++ bool up; ++ bool clk; ++ uint now; ++ u16 vid; ++ u16 did; ++ uint chip; ++ uint chiprev; ++ uint chippkg; ++ uint sromrev; ++ uint boardtype; ++ uint boardrev; ++ uint boardvendor; ++ u32 boardflags; ++ u32 boardflags2; ++ uint buscorerev; ++ uint fast_timer; ++ uint slow_timer; ++ uint glacial_timer; ++ u8 rx_antdiv; ++ s8 phy_noise_window[MA_WINDOW_SZ]; ++ uint phy_noise_index; ++ u8 hw_phytxchain; ++ u8 hw_phyrxchain; ++ u8 phytxchain; ++ u8 phyrxchain; ++ u8 rssi_mode; ++ bool _rifs_phy; ++}; ++ ++struct brcms_phy_pub { ++ uint phy_type; ++ uint phy_rev; ++ u8 phy_corenum; ++ u16 radioid; ++ u8 radiorev; ++ u8 radiover; ++ ++ uint coreflags; ++ uint ana_rev; ++ bool abgphy_encore; ++}; ++ ++struct phy_func_ptr { ++ void (*init)(struct brcms_phy *); ++ void (*calinit)(struct brcms_phy *); ++ void (*chanset)(struct brcms_phy *, u16 chanspec); ++ void (*txpwrrecalc)(struct brcms_phy *); ++ int (*longtrn)(struct brcms_phy *, int); ++ void (*txiqccget)(struct brcms_phy *, u16 *, u16 *); ++ void (*txiqccset)(struct brcms_phy *, u16, u16); ++ u16 (*txloccget)(struct brcms_phy *); ++ void (*radioloftget)(struct brcms_phy *, u8 *, u8 *, u8 *, u8 *); ++ void (*carrsuppr)(struct brcms_phy *); ++ s32 (*rxsigpwr)(struct brcms_phy *, s32); ++ void (*detach)(struct brcms_phy *); ++}; ++ ++struct brcms_phy { ++ struct brcms_phy_pub pubpi_ro; ++ struct shared_phy *sh; ++ struct phy_func_ptr pi_fptr; ++ ++ union { ++ struct brcms_phy_lcnphy *pi_lcnphy; ++ } u; ++ bool user_txpwr_at_rfport; ++ ++ struct d11regs __iomem *regs; ++ struct brcms_phy *next; ++ struct brcms_phy_pub pubpi; ++ ++ bool do_initcal; ++ bool phytest_on; ++ bool ofdm_rateset_war; ++ bool bf_preempt_4306; ++ u16 radio_chanspec; ++ u8 antsel_type; ++ u16 bw; ++ u8 txpwr_percent; ++ bool phy_init_por; ++ ++ bool init_in_progress; ++ bool initialized; ++ bool sbtml_gm; ++ uint refcnt; ++ bool watchdog_override; ++ u8 phynoise_state; ++ uint phynoise_now; ++ int phynoise_chan_watchdog; ++ bool phynoise_polling; ++ bool disable_percal; ++ u32 measure_hold; ++ ++ s16 txpa_2g[PWRTBL_NUM_COEFF]; ++ s16 txpa_2g_low_temp[PWRTBL_NUM_COEFF]; ++ s16 txpa_2g_high_temp[PWRTBL_NUM_COEFF]; ++ s16 txpa_5g_low[PWRTBL_NUM_COEFF]; ++ s16 txpa_5g_mid[PWRTBL_NUM_COEFF]; ++ s16 txpa_5g_hi[PWRTBL_NUM_COEFF]; ++ ++ u8 tx_srom_max_2g; ++ u8 tx_srom_max_5g_low; ++ u8 tx_srom_max_5g_mid; ++ u8 tx_srom_max_5g_hi; ++ u8 tx_srom_max_rate_2g[TXP_NUM_RATES]; ++ u8 tx_srom_max_rate_5g_low[TXP_NUM_RATES]; ++ u8 tx_srom_max_rate_5g_mid[TXP_NUM_RATES]; ++ u8 tx_srom_max_rate_5g_hi[TXP_NUM_RATES]; ++ u8 tx_user_target[TXP_NUM_RATES]; ++ s8 tx_power_offset[TXP_NUM_RATES]; ++ u8 tx_power_target[TXP_NUM_RATES]; ++ ++ struct brcms_phy_srom_fem srom_fem2g; ++ struct brcms_phy_srom_fem srom_fem5g; ++ ++ u8 tx_power_max; ++ u8 tx_power_max_rate_ind; ++ bool hwpwrctrl; ++ u8 nphy_txpwrctrl; ++ s8 nphy_txrx_chain; ++ bool phy_5g_pwrgain; ++ ++ u16 phy_wreg; ++ u16 phy_wreg_limit; ++ ++ s8 n_preamble_override; ++ u8 antswitch; ++ u8 aa2g, aa5g; ++ ++ s8 idle_tssi[CH_5G_GROUP]; ++ s8 target_idle_tssi; ++ s8 txpwr_est_Pout; ++ u8 tx_power_min; ++ u8 txpwr_limit[TXP_NUM_RATES]; ++ u8 txpwr_env_limit[TXP_NUM_RATES]; ++ u8 adj_pwr_tbl_nphy[ADJ_PWR_TBL_LEN]; ++ ++ bool channel_14_wide_filter; ++ ++ bool txpwroverride; ++ bool txpwridx_override_aphy; ++ s16 radiopwr_override; ++ u16 hwpwr_txcur; ++ u8 saved_txpwr_idx; ++ ++ bool edcrs_threshold_lock; ++ ++ u32 tr_R_gain_val; ++ u32 tr_T_gain_val; ++ ++ s16 ofdm_analog_filt_bw_override; ++ s16 cck_analog_filt_bw_override; ++ s16 ofdm_rccal_override; ++ s16 cck_rccal_override; ++ u16 extlna_type; ++ ++ uint interference_mode_crs_time; ++ u16 crsglitch_prev; ++ bool interference_mode_crs; ++ ++ u32 phy_tx_tone_freq; ++ uint phy_lastcal; ++ bool phy_forcecal; ++ bool phy_fixed_noise; ++ u32 xtalfreq; ++ u8 pdiv; ++ s8 carrier_suppr_disable; ++ ++ bool phy_bphy_evm; ++ bool phy_bphy_rfcs; ++ s8 phy_scraminit; ++ u8 phy_gpiosel; ++ ++ s16 phy_txcore_disable_temp; ++ s16 phy_txcore_enable_temp; ++ s8 phy_tempsense_offset; ++ bool phy_txcore_heatedup; ++ ++ u16 radiopwr; ++ u16 bb_atten; ++ u16 txctl1; ++ ++ u16 mintxbias; ++ u16 mintxmag; ++ struct lo_complex_abgphy_info gphy_locomp_iq ++ [STATIC_NUM_RF][STATIC_NUM_BB]; ++ s8 stats_11b_txpower[STATIC_NUM_RF][STATIC_NUM_BB]; ++ u16 gain_table[TX_GAIN_TABLE_LENGTH]; ++ bool loopback_gain; ++ s16 max_lpback_gain_hdB; ++ s16 trsw_rx_gain_hdB; ++ u8 power_vec[8]; ++ ++ u16 rc_cal; ++ int nrssi_table_delta; ++ int nrssi_slope_scale; ++ int nrssi_slope_offset; ++ int min_rssi; ++ int max_rssi; ++ ++ s8 txpwridx; ++ u8 min_txpower; ++ ++ u8 a_band_high_disable; ++ ++ u16 tx_vos; ++ u16 global_tx_bb_dc_bias_loft; ++ ++ int rf_max; ++ int bb_max; ++ int rf_list_size; ++ int bb_list_size; ++ u16 *rf_attn_list; ++ u16 *bb_attn_list; ++ u16 padmix_mask; ++ u16 padmix_reg; ++ u16 *txmag_list; ++ uint txmag_len; ++ bool txmag_enable; ++ ++ s8 *a_tssi_to_dbm; ++ s8 *m_tssi_to_dbm; ++ s8 *l_tssi_to_dbm; ++ s8 *h_tssi_to_dbm; ++ u8 *hwtxpwr; ++ ++ u16 freqtrack_saved_regs[2]; ++ int cur_interference_mode; ++ bool hwpwrctrl_capable; ++ bool temppwrctrl_capable; ++ ++ uint phycal_nslope; ++ uint phycal_noffset; ++ uint phycal_mlo; ++ uint phycal_txpower; ++ ++ u8 phy_aa2g; ++ ++ bool nphy_tableloaded; ++ s8 nphy_rssisel; ++ u32 nphy_bb_mult_save; ++ u16 nphy_txiqlocal_bestc[11]; ++ bool nphy_txiqlocal_coeffsvalid; ++ struct nphy_txpwrindex nphy_txpwrindex[PHY_CORE_NUM_2]; ++ struct nphy_pwrctrl nphy_pwrctrl_info[PHY_CORE_NUM_2]; ++ u16 cck2gpo; ++ u32 ofdm2gpo; ++ u32 ofdm5gpo; ++ u32 ofdm5glpo; ++ u32 ofdm5ghpo; ++ u8 bw402gpo; ++ u8 bw405gpo; ++ u8 bw405glpo; ++ u8 bw405ghpo; ++ u8 cdd2gpo; ++ u8 cdd5gpo; ++ u8 cdd5glpo; ++ u8 cdd5ghpo; ++ u8 stbc2gpo; ++ u8 stbc5gpo; ++ u8 stbc5glpo; ++ u8 stbc5ghpo; ++ u8 bwdup2gpo; ++ u8 bwdup5gpo; ++ u8 bwdup5glpo; ++ u8 bwdup5ghpo; ++ u16 mcs2gpo[8]; ++ u16 mcs5gpo[8]; ++ u16 mcs5glpo[8]; ++ u16 mcs5ghpo[8]; ++ u32 nphy_rxcalparams; ++ ++ u8 phy_spuravoid; ++ bool phy_isspuravoid; ++ ++ u8 phy_pabias; ++ u8 nphy_papd_skip; ++ u8 nphy_tssi_slope; ++ ++ s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ]; ++ u8 nphy_noise_index; ++ ++ u8 nphy_txpid2g[PHY_CORE_NUM_2]; ++ u8 nphy_txpid5g[PHY_CORE_NUM_2]; ++ u8 nphy_txpid5gl[PHY_CORE_NUM_2]; ++ u8 nphy_txpid5gh[PHY_CORE_NUM_2]; ++ ++ bool nphy_gain_boost; ++ bool nphy_elna_gain_config; ++ u16 old_bphy_test; ++ u16 old_bphy_testcontrol; ++ ++ bool phyhang_avoid; ++ ++ bool rssical_nphy; ++ u8 nphy_perical; ++ uint nphy_perical_last; ++ u8 cal_type_override; ++ u8 mphase_cal_phase_id; ++ u8 mphase_txcal_cmdidx; ++ u8 mphase_txcal_numcmds; ++ u16 mphase_txcal_bestcoeffs[11]; ++ u16 nphy_txiqlocal_chanspec; ++ u16 nphy_iqcal_chanspec_2G; ++ u16 nphy_iqcal_chanspec_5G; ++ u16 nphy_rssical_chanspec_2G; ++ u16 nphy_rssical_chanspec_5G; ++ struct wlapi_timer *phycal_timer; ++ bool use_int_tx_iqlo_cal_nphy; ++ bool internal_tx_iqlo_cal_tapoff_intpa_nphy; ++ s16 nphy_lastcal_temp; ++ ++ struct txiqcal_cache calibration_cache; ++ struct rssical_cache rssical_cache; ++ ++ u8 nphy_txpwr_idx[2]; ++ u8 nphy_papd_cal_type; ++ uint nphy_papd_last_cal; ++ u16 nphy_papd_tx_gain_at_last_cal[2]; ++ u8 nphy_papd_cal_gain_index[2]; ++ s16 nphy_papd_epsilon_offset[2]; ++ bool nphy_papd_recal_enable; ++ u32 nphy_papd_recal_counter; ++ bool nphy_force_papd_cal; ++ bool nphy_papdcomp; ++ bool ipa2g_on; ++ bool ipa5g_on; ++ ++ u16 classifier_state; ++ u16 clip_state[2]; ++ uint nphy_deaf_count; ++ u8 rxiq_samps; ++ u8 rxiq_antsel; ++ ++ u16 rfctrlIntc1_save; ++ u16 rfctrlIntc2_save; ++ bool first_cal_after_assoc; ++ u16 tx_rx_cal_radio_saveregs[22]; ++ u16 tx_rx_cal_phy_saveregs[15]; ++ ++ u8 nphy_cal_orig_pwr_idx[2]; ++ u8 nphy_txcal_pwr_idx[2]; ++ u8 nphy_rxcal_pwr_idx[2]; ++ u16 nphy_cal_orig_tx_gain[2]; ++ struct nphy_txgains nphy_cal_target_gain; ++ u16 nphy_txcal_bbmult; ++ u16 nphy_gmval; ++ ++ u16 nphy_saved_bbconf; ++ ++ bool nphy_gband_spurwar_en; ++ bool nphy_gband_spurwar2_en; ++ bool nphy_aband_spurwar_en; ++ u16 nphy_rccal_value; ++ u16 nphy_crsminpwr[3]; ++ struct nphy_noisevar_buf nphy_saved_noisevars; ++ bool nphy_anarxlpf_adjusted; ++ bool nphy_crsminpwr_adjusted; ++ bool nphy_noisevars_adjusted; ++ ++ bool nphy_rxcal_active; ++ u16 radar_percal_mask; ++ bool dfs_lp_buffer_nphy; ++ ++ u16 nphy_fineclockgatecontrol; ++ ++ s8 rx2tx_biasentry; ++ ++ u16 crsminpwr0; ++ u16 crsminpwrl0; ++ u16 crsminpwru0; ++ s16 noise_crsminpwr_index; ++ u16 init_gain_core1; ++ u16 init_gain_core2; ++ u16 init_gainb_core1; ++ u16 init_gainb_core2; ++ u8 aci_noise_curr_channel; ++ u16 init_gain_rfseq[4]; ++ ++ bool radio_is_on; ++ ++ bool nphy_sample_play_lpf_bw_ctl_ovr; ++ ++ u16 tbl_data_hi; ++ u16 tbl_data_lo; ++ u16 tbl_addr; ++ ++ uint tbl_save_id; ++ uint tbl_save_offset; ++ ++ u8 txpwrctrl; ++ s8 txpwrindex[PHY_CORE_MAX]; ++ ++ u8 phycal_tempdelta; ++ u32 mcs20_po; ++ u32 mcs40_po; ++ struct wiphy *wiphy; ++}; ++ ++struct cs32 { ++ s32 q; ++ s32 i; ++}; ++ ++struct radio_regs { ++ u16 address; ++ u32 init_a; ++ u32 init_g; ++ u8 do_init_a; ++ u8 do_init_g; ++}; ++ ++struct radio_20xx_regs { ++ u16 address; ++ u8 init; ++ u8 do_init; ++}; ++ ++struct lcnphy_radio_regs { ++ u16 address; ++ u8 init_a; ++ u8 init_g; ++ u8 do_init_a; ++ u8 do_init_g; ++}; ++ ++extern u16 read_phy_reg(struct brcms_phy *pi, u16 addr); ++extern void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); ++extern void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); ++extern void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); ++extern void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val); ++ ++extern u16 read_radio_reg(struct brcms_phy *pi, u16 addr); ++extern void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); ++extern void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); ++extern void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, ++ u16 val); ++extern void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask); ++ ++extern void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); ++ ++extern void wlc_phyreg_enter(struct brcms_phy_pub *pih); ++extern void wlc_phyreg_exit(struct brcms_phy_pub *pih); ++extern void wlc_radioreg_enter(struct brcms_phy_pub *pih); ++extern void wlc_radioreg_exit(struct brcms_phy_pub *pih); ++ ++extern void wlc_phy_read_table(struct brcms_phy *pi, ++ const struct phytbl_info *ptbl_info, ++ u16 tblAddr, u16 tblDataHi, ++ u16 tblDatalo); ++extern void wlc_phy_write_table(struct brcms_phy *pi, ++ const struct phytbl_info *ptbl_info, ++ u16 tblAddr, u16 tblDataHi, u16 tblDatalo); ++extern void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, ++ uint tbl_offset, u16 tblAddr, u16 tblDataHi, ++ u16 tblDataLo); ++extern void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); ++ ++extern void write_phy_channel_reg(struct brcms_phy *pi, uint val); ++extern void wlc_phy_txpower_update_shm(struct brcms_phy *pi); ++ ++extern u8 wlc_phy_nbits(s32 value); ++extern void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core); ++ ++extern uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, ++ struct radio_20xx_regs *radioregs); ++extern uint wlc_phy_init_radio_regs(struct brcms_phy *pi, ++ const struct radio_regs *radioregs, ++ u16 core_offset); ++ ++extern void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi); ++ ++extern void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on); ++extern void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, ++ s32 *eps_imag); ++ ++extern void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); ++extern void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); ++ ++extern bool wlc_phy_attach_nphy(struct brcms_phy *pi); ++extern bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_detach_lcnphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_init_nphy(struct brcms_phy *pi); ++extern void wlc_phy_init_lcnphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_cal_init_nphy(struct brcms_phy *pi); ++extern void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, ++ u16 chanspec); ++extern void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, ++ u16 chanspec); ++extern void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi, ++ u16 chanspec); ++extern int wlc_phy_channel2freq(uint channel); ++extern int wlc_phy_chanspec_freq2bandrange_lpssn(uint); ++extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec); ++ ++extern void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode); ++extern s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi); ++ ++extern void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi); ++extern void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi); ++extern void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi); ++ ++extern void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index); ++extern void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable); ++extern void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi); ++extern void wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, ++ u16 max_val, bool iqcalmode); ++ ++extern void wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, ++ u8 *max_pwr, u8 rate_id); ++extern void wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, ++ u8 rate_mcs_end, ++ u8 rate_ofdm_start); ++extern void wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, ++ u8 rate_ofdm_start, ++ u8 rate_ofdm_end, ++ u8 rate_mcs_start); ++ ++extern u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode); ++extern s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode); ++extern s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); ++extern s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); ++extern void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); ++extern void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); ++extern void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); ++extern void wlc_2064_vco_cal(struct brcms_phy *pi); ++ ++extern void wlc_phy_txpower_recalc_target(struct brcms_phy *pi); ++ ++#define LCNPHY_TBL_ID_PAPDCOMPDELTATBL 0x18 ++#define LCNPHY_TX_POWER_TABLE_SIZE 128 ++#define LCNPHY_MAX_TX_POWER_INDEX (LCNPHY_TX_POWER_TABLE_SIZE - 1) ++#define LCNPHY_TBL_ID_TXPWRCTL 0x07 ++#define LCNPHY_TX_PWR_CTRL_OFF 0 ++#define LCNPHY_TX_PWR_CTRL_SW (0x1 << 15) ++#define LCNPHY_TX_PWR_CTRL_HW ((0x1 << 15) | \ ++ (0x1 << 14) | \ ++ (0x1 << 13)) ++ ++#define LCNPHY_TX_PWR_CTRL_TEMPBASED 0xE001 ++ ++extern void wlc_lcnphy_write_table(struct brcms_phy *pi, ++ const struct phytbl_info *pti); ++extern void wlc_lcnphy_read_table(struct brcms_phy *pi, ++ struct phytbl_info *pti); ++extern void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b); ++extern void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq); ++extern void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b); ++extern u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi); ++extern void wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, u8 *ei0, ++ u8 *eq0, u8 *fi0, u8 *fq0); ++extern void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode); ++extern void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode); ++extern bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi); ++extern void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi); ++extern s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1); ++extern void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, ++ s8 *cck_pwr); ++extern void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi); ++ ++extern s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index); ++ ++#define NPHY_MAX_HPVGA1_INDEX 10 ++#define NPHY_DEF_HPVGA1_INDEXLIMIT 7 ++ ++struct phy_iq_est { ++ s32 iq_prod; ++ u32 i_pwr; ++ u32 q_pwr; ++}; ++ ++extern void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, ++ bool enable); ++extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode); ++ ++#define wlc_phy_write_table_nphy(pi, pti) \ ++ wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73) ++ ++#define wlc_phy_read_table_nphy(pi, pti) \ ++ wlc_phy_read_table(pi, pti, 0x72, 0x74, 0x73) ++ ++#define wlc_nphy_table_addr(pi, id, off) \ ++ wlc_phy_table_addr((pi), (id), (off), 0x72, 0x74, 0x73) ++ ++#define wlc_nphy_table_data_write(pi, w, v) \ ++ wlc_phy_table_data_write((pi), (w), (v)) ++ ++extern void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o, ++ u32 w, void *d); ++extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32, ++ u32, const void *); ++ ++#define PHY_IPA(pi) \ ++ ((pi->ipa2g_on && CHSPEC_IS2G(pi->radio_chanspec)) || \ ++ (pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec))) ++ ++#define BRCMS_PHY_WAR_PR51571(pi) \ ++ if (NREV_LT((pi)->pubpi.phy_rev, 3)) \ ++ (void)R_REG(&(pi)->regs->maccontrol) ++ ++extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype); ++extern void wlc_phy_aci_reset_nphy(struct brcms_phy *pi); ++extern void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en); ++ ++extern u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint chan); ++extern void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on); ++ ++extern void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd); ++extern s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi); ++ ++extern u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val); ++ ++extern void wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, ++ u16 num_samps, u8 wait_time, ++ u8 wait_for_crs); ++ ++extern void wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, ++ struct nphy_iq_comp *comp); ++extern void wlc_phy_aci_and_noise_reduction_nphy(struct brcms_phy *pi); ++ ++extern void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, ++ u8 rxcore_bitmask); ++extern u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih); ++ ++extern void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type); ++extern void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi); ++extern void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi); ++extern void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi); ++extern u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi); ++ ++extern struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi); ++extern int wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, ++ struct nphy_txgains target_gain, ++ bool full, bool m); ++extern int wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, ++ struct nphy_txgains target_gain, ++ u8 type, bool d); ++extern void wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, ++ s8 txpwrindex, bool res); ++extern void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core, u8 rssi_type); ++extern int wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, ++ s32 *rssi_buf, u8 nsamps); ++extern void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi); ++extern int wlc_phy_aci_scan_nphy(struct brcms_phy *pi); ++extern void wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, ++ s32 dBm_targetpower, bool debug); ++extern int wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, ++ u8 mode, u8, bool); ++extern void wlc_phy_stopplayback_nphy(struct brcms_phy *pi); ++extern void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, ++ u8 num_samps); ++extern void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi); ++ ++extern int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, ++ struct d11rxhdr *rxh); ++ ++#define NPHY_TESTPATTERN_BPHY_EVM 0 ++#define NPHY_TESTPATTERN_BPHY_RFCS 1 ++ ++extern void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs); ++ ++void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, ++ s8 *ofdmoffset); ++extern s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, ++ u16 chanspec); ++ ++extern bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih); ++#endif /* _BRCM_PHY_INT_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c.orig 2011-11-09 13:46:58.257800483 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c 2011-11-09 13:47:17.012566015 -0500 +@@ -0,0 +1,5154 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include "phy_qmath.h" ++#include "phy_hal.h" ++#include "phy_radio.h" ++#include "phytbl_lcn.h" ++#include "phy_lcn.h" ++ ++#define PLL_2064_NDIV 90 ++#define PLL_2064_LOW_END_VCO 3000 ++#define PLL_2064_LOW_END_KVCO 27 ++#define PLL_2064_HIGH_END_VCO 4200 ++#define PLL_2064_HIGH_END_KVCO 68 ++#define PLL_2064_LOOP_BW_DOUBLER 200 ++#define PLL_2064_D30_DOUBLER 10500 ++#define PLL_2064_LOOP_BW 260 ++#define PLL_2064_D30 8000 ++#define PLL_2064_CAL_REF_TO 8 ++#define PLL_2064_MHZ 1000000 ++#define PLL_2064_OPEN_LOOP_DELAY 5 ++ ++#define TEMPSENSE 1 ++#define VBATSENSE 2 ++ ++#define NOISE_IF_UPD_CHK_INTERVAL 1 ++#define NOISE_IF_UPD_RST_INTERVAL 60 ++#define NOISE_IF_UPD_THRESHOLD_CNT 1 ++#define NOISE_IF_UPD_TRHRESHOLD 50 ++#define NOISE_IF_UPD_TIMEOUT 1000 ++#define NOISE_IF_OFF 0 ++#define NOISE_IF_CHK 1 ++#define NOISE_IF_ON 2 ++ ++#define PAPD_BLANKING_PROFILE 3 ++#define PAPD2LUT 0 ++#define PAPD_CORR_NORM 0 ++#define PAPD_BLANKING_THRESHOLD 0 ++#define PAPD_STOP_AFTER_LAST_UPDATE 0 ++ ++#define LCN_TARGET_PWR 60 ++ ++#define LCN_VBAT_OFFSET_433X 34649679 ++#define LCN_VBAT_SLOPE_433X 8258032 ++ ++#define LCN_VBAT_SCALE_NOM 53 ++#define LCN_VBAT_SCALE_DEN 432 ++ ++#define LCN_TEMPSENSE_OFFSET 80812 ++#define LCN_TEMPSENSE_DEN 2647 ++ ++#define LCN_BW_LMT 200 ++#define LCN_CUR_LMT 1250 ++#define LCN_MULT 1 ++#define LCN_VCO_DIV 30 ++#define LCN_OFFSET 680 ++#define LCN_FACT 490 ++#define LCN_CUR_DIV 2640 ++ ++#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \ ++ (0 + 8) ++#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \ ++ (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT) ++ ++#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \ ++ (0 + 8) ++#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \ ++ (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT) ++ ++#define wlc_lcnphy_enable_tx_gain_override(pi) \ ++ wlc_lcnphy_set_tx_gain_override(pi, true) ++#define wlc_lcnphy_disable_tx_gain_override(pi) \ ++ wlc_lcnphy_set_tx_gain_override(pi, false) ++ ++#define wlc_lcnphy_iqcal_active(pi) \ ++ (read_phy_reg((pi), 0x451) & \ ++ ((0x1 << 15) | (0x1 << 14))) ++ ++#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13)) ++#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \ ++ (pi->temppwrctrl_capable) ++#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \ ++ (pi->hwpwrctrl_capable) ++ ++#define SWCTRL_BT_TX 0x18 ++#define SWCTRL_OVR_DISABLE 0x40 ++ ++#define AFE_CLK_INIT_MODE_TXRX2X 1 ++#define AFE_CLK_INIT_MODE_PAPD 0 ++ ++#define LCNPHY_TBL_ID_IQLOCAL 0x00 ++ ++#define LCNPHY_TBL_ID_RFSEQ 0x08 ++#define LCNPHY_TBL_ID_GAIN_IDX 0x0d ++#define LCNPHY_TBL_ID_SW_CTRL 0x0f ++#define LCNPHY_TBL_ID_GAIN_TBL 0x12 ++#define LCNPHY_TBL_ID_SPUR 0x14 ++#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15 ++#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16 ++ ++#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832 ++#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128 ++#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192 ++#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320 ++#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448 ++#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576 ++ ++#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140 ++ ++#define LCNPHY_TX_PWR_CTRL_START_NPT 1 ++#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7 ++ ++#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000 ++ ++#define LCNPHY_ACI_DETECT_START 1 ++#define LCNPHY_ACI_DETECT_PROGRESS 2 ++#define LCNPHY_ACI_DETECT_STOP 3 ++ ++#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100 ++#define LCNPHY_ACI_GLITCH_TRSH 2000 ++#define LCNPHY_ACI_TMOUT 250 ++#define LCNPHY_ACI_DETECT_TIMEOUT 2 ++#define LCNPHY_ACI_START_DELAY 0 ++ ++#define wlc_lcnphy_tx_gain_override_enabled(pi) \ ++ (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6))) ++ ++#define wlc_lcnphy_total_tx_frames(pi) \ ++ wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \ ++ offsetof(struct macstat, txallfrm)) ++ ++struct lcnphy_txgains { ++ u16 gm_gain; ++ u16 pga_gain; ++ u16 pad_gain; ++ u16 dac_gain; ++}; ++ ++enum lcnphy_cal_mode { ++ LCNPHY_CAL_FULL, ++ LCNPHY_CAL_RECAL, ++ LCNPHY_CAL_CURRECAL, ++ LCNPHY_CAL_DIGCAL, ++ LCNPHY_CAL_GCTRL ++}; ++ ++struct lcnphy_rx_iqcomp { ++ u8 chan; ++ s16 a; ++ s16 b; ++}; ++ ++struct lcnphy_spb_tone { ++ s16 re; ++ s16 im; ++}; ++ ++struct lcnphy_unsign16_struct { ++ u16 re; ++ u16 im; ++}; ++ ++struct lcnphy_iq_est { ++ u32 iq_prod; ++ u32 i_pwr; ++ u32 q_pwr; ++}; ++ ++struct lcnphy_sfo_cfg { ++ u16 ptcentreTs20; ++ u16 ptcentreFactor; ++}; ++ ++enum lcnphy_papd_cal_type { ++ LCNPHY_PAPD_CAL_CW, ++ LCNPHY_PAPD_CAL_OFDM ++}; ++ ++typedef u16 iqcal_gain_params_lcnphy[9]; ++ ++static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = { ++ {0, 0, 0, 0, 0, 0, 0, 0, 0}, ++}; ++ ++static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = { ++ tbl_iqcal_gainparams_lcnphy_2G, ++}; ++ ++static const u16 iqcal_gainparams_numgains_lcnphy[1] = { ++ sizeof(tbl_iqcal_gainparams_lcnphy_2G) / ++ sizeof(*tbl_iqcal_gainparams_lcnphy_2G), ++}; ++ ++static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = { ++ {965, 1087}, ++ {967, 1085}, ++ {969, 1082}, ++ {971, 1080}, ++ {973, 1078}, ++ {975, 1076}, ++ {977, 1073}, ++ {979, 1071}, ++ {981, 1069}, ++ {983, 1067}, ++ {985, 1065}, ++ {987, 1063}, ++ {989, 1060}, ++ {994, 1055} ++}; ++ ++static const ++u16 lcnphy_iqcal_loft_gainladder[] = { ++ ((2 << 8) | 0), ++ ((3 << 8) | 0), ++ ((4 << 8) | 0), ++ ((6 << 8) | 0), ++ ((8 << 8) | 0), ++ ((11 << 8) | 0), ++ ((16 << 8) | 0), ++ ((16 << 8) | 1), ++ ((16 << 8) | 2), ++ ((16 << 8) | 3), ++ ((16 << 8) | 4), ++ ((16 << 8) | 5), ++ ((16 << 8) | 6), ++ ((16 << 8) | 7), ++ ((23 << 8) | 7), ++ ((32 << 8) | 7), ++ ((45 << 8) | 7), ++ ((64 << 8) | 7), ++ ((91 << 8) | 7), ++ ((128 << 8) | 7) ++}; ++ ++static const ++u16 lcnphy_iqcal_ir_gainladder[] = { ++ ((1 << 8) | 0), ++ ((2 << 8) | 0), ++ ((4 << 8) | 0), ++ ((6 << 8) | 0), ++ ((8 << 8) | 0), ++ ((11 << 8) | 0), ++ ((16 << 8) | 0), ++ ((23 << 8) | 0), ++ ((32 << 8) | 0), ++ ((45 << 8) | 0), ++ ((64 << 8) | 0), ++ ((64 << 8) | 1), ++ ((64 << 8) | 2), ++ ((64 << 8) | 3), ++ ((64 << 8) | 4), ++ ((64 << 8) | 5), ++ ((64 << 8) | 6), ++ ((64 << 8) | 7), ++ ((91 << 8) | 7), ++ ((128 << 8) | 7) ++}; ++ ++static const ++struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = { ++ {88, 0}, ++ {73, 49}, ++ {34, 81}, ++ {-17, 86}, ++ {-62, 62}, ++ {-86, 17}, ++ {-81, -34}, ++ {-49, -73}, ++ {0, -88}, ++ {49, -73}, ++ {81, -34}, ++ {86, 17}, ++ {62, 62}, ++ {17, 86}, ++ {-34, 81}, ++ {-73, 49}, ++ {-88, 0}, ++ {-73, -49}, ++ {-34, -81}, ++ {17, -86}, ++ {62, -62}, ++ {86, -17}, ++ {81, 34}, ++ {49, 73}, ++ {0, 88}, ++ {-49, 73}, ++ {-81, 34}, ++ {-86, -17}, ++ {-62, -62}, ++ {-17, -86}, ++ {34, -81}, ++ {73, -49}, ++}; ++ ++static const ++u16 iqlo_loopback_rf_regs[20] = { ++ RADIO_2064_REG036, ++ RADIO_2064_REG11A, ++ RADIO_2064_REG03A, ++ RADIO_2064_REG025, ++ RADIO_2064_REG028, ++ RADIO_2064_REG005, ++ RADIO_2064_REG112, ++ RADIO_2064_REG0FF, ++ RADIO_2064_REG11F, ++ RADIO_2064_REG00B, ++ RADIO_2064_REG113, ++ RADIO_2064_REG007, ++ RADIO_2064_REG0FC, ++ RADIO_2064_REG0FD, ++ RADIO_2064_REG012, ++ RADIO_2064_REG057, ++ RADIO_2064_REG059, ++ RADIO_2064_REG05C, ++ RADIO_2064_REG078, ++ RADIO_2064_REG092, ++}; ++ ++static const ++u16 tempsense_phy_regs[14] = { ++ 0x503, ++ 0x4a4, ++ 0x4d0, ++ 0x4d9, ++ 0x4da, ++ 0x4a6, ++ 0x938, ++ 0x939, ++ 0x4d8, ++ 0x4d0, ++ 0x4d7, ++ 0x4a5, ++ 0x40d, ++ 0x4a2, ++}; ++ ++static const ++u16 rxiq_cal_rf_reg[11] = { ++ RADIO_2064_REG098, ++ RADIO_2064_REG116, ++ RADIO_2064_REG12C, ++ RADIO_2064_REG06A, ++ RADIO_2064_REG00B, ++ RADIO_2064_REG01B, ++ RADIO_2064_REG113, ++ RADIO_2064_REG01D, ++ RADIO_2064_REG114, ++ RADIO_2064_REG02E, ++ RADIO_2064_REG12A, ++}; ++ ++static const ++struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = { ++ {1, 0, 0}, ++ {2, 0, 0}, ++ {3, 0, 0}, ++ {4, 0, 0}, ++ {5, 0, 0}, ++ {6, 0, 0}, ++ {7, 0, 0}, ++ {8, 0, 0}, ++ {9, 0, 0}, ++ {10, 0, 0}, ++ {11, 0, 0}, ++ {12, 0, 0}, ++ {13, 0, 0}, ++ {14, 0, 0}, ++ {34, 0, 0}, ++ {38, 0, 0}, ++ {42, 0, 0}, ++ {46, 0, 0}, ++ {36, 0, 0}, ++ {40, 0, 0}, ++ {44, 0, 0}, ++ {48, 0, 0}, ++ {52, 0, 0}, ++ {56, 0, 0}, ++ {60, 0, 0}, ++ {64, 0, 0}, ++ {100, 0, 0}, ++ {104, 0, 0}, ++ {108, 0, 0}, ++ {112, 0, 0}, ++ {116, 0, 0}, ++ {120, 0, 0}, ++ {124, 0, 0}, ++ {128, 0, 0}, ++ {132, 0, 0}, ++ {136, 0, 0}, ++ {140, 0, 0}, ++ {149, 0, 0}, ++ {153, 0, 0}, ++ {157, 0, 0}, ++ {161, 0, 0}, ++ {165, 0, 0}, ++ {184, 0, 0}, ++ {188, 0, 0}, ++ {192, 0, 0}, ++ {196, 0, 0}, ++ {200, 0, 0}, ++ {204, 0, 0}, ++ {208, 0, 0}, ++ {212, 0, 0}, ++ {216, 0, 0}, ++}; ++ ++static const u32 lcnphy_23bitgaincode_table[] = { ++ 0x200100, ++ 0x200200, ++ 0x200004, ++ 0x200014, ++ 0x200024, ++ 0x200034, ++ 0x200134, ++ 0x200234, ++ 0x200334, ++ 0x200434, ++ 0x200037, ++ 0x200137, ++ 0x200237, ++ 0x200337, ++ 0x200437, ++ 0x000035, ++ 0x000135, ++ 0x000235, ++ 0x000037, ++ 0x000137, ++ 0x000237, ++ 0x000337, ++ 0x00013f, ++ 0x00023f, ++ 0x00033f, ++ 0x00034f, ++ 0x00044f, ++ 0x00144f, ++ 0x00244f, ++ 0x00254f, ++ 0x00354f, ++ 0x00454f, ++ 0x00464f, ++ 0x01464f, ++ 0x02464f, ++ 0x03464f, ++ 0x04464f, ++}; ++ ++static const s8 lcnphy_gain_table[] = { ++ -16, ++ -13, ++ 10, ++ 7, ++ 4, ++ 0, ++ 3, ++ 6, ++ 9, ++ 12, ++ 15, ++ 18, ++ 21, ++ 24, ++ 27, ++ 30, ++ 33, ++ 36, ++ 39, ++ 42, ++ 45, ++ 48, ++ 50, ++ 53, ++ 56, ++ 59, ++ 62, ++ 65, ++ 68, ++ 71, ++ 74, ++ 77, ++ 80, ++ 83, ++ 86, ++ 89, ++ 92, ++}; ++ ++static const s8 lcnphy_gain_index_offset_for_rssi[] = { ++ 7, ++ 7, ++ 7, ++ 7, ++ 7, ++ 7, ++ 7, ++ 8, ++ 7, ++ 7, ++ 6, ++ 7, ++ 7, ++ 4, ++ 4, ++ 4, ++ 4, ++ 4, ++ 4, ++ 4, ++ 4, ++ 3, ++ 3, ++ 3, ++ 3, ++ 3, ++ 3, ++ 4, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ 2, ++ -1, ++ -2, ++ -2, ++ -2 ++}; ++ ++struct chan_info_2064_lcnphy { ++ uint chan; ++ uint freq; ++ u8 logen_buftune; ++ u8 logen_rccr_tx; ++ u8 txrf_mix_tune_ctrl; ++ u8 pa_input_tune_g; ++ u8 logen_rccr_rx; ++ u8 pa_rxrf_lna1_freq_tune; ++ u8 pa_rxrf_lna2_freq_tune; ++ u8 rxrf_rxrf_spare1; ++}; ++ ++static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = { ++ {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++ {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, ++}; ++ ++static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = { ++ {0x00, 0, 0, 0, 0}, ++ {0x01, 0x64, 0x64, 0, 0}, ++ {0x02, 0x20, 0x20, 0, 0}, ++ {0x03, 0x66, 0x66, 0, 0}, ++ {0x04, 0xf8, 0xf8, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0x10, 0x10, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0x37, 0x37, 0, 0}, ++ {0x0B, 0x6, 0x6, 0, 0}, ++ {0x0C, 0x55, 0x55, 0, 0}, ++ {0x0D, 0x8b, 0x8b, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0x5, 0x5, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0xe, 0xe, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0xb, 0xb, 0, 0}, ++ {0x14, 0x2, 0x2, 0, 0}, ++ {0x15, 0x12, 0x12, 0, 0}, ++ {0x16, 0x12, 0x12, 0, 0}, ++ {0x17, 0xc, 0xc, 0, 0}, ++ {0x18, 0xc, 0xc, 0, 0}, ++ {0x19, 0xc, 0xc, 0, 0}, ++ {0x1A, 0x8, 0x8, 0, 0}, ++ {0x1B, 0x2, 0x2, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0x1, 0x1, 0, 0}, ++ {0x1E, 0x12, 0x12, 0, 0}, ++ {0x1F, 0x6e, 0x6e, 0, 0}, ++ {0x20, 0x2, 0x2, 0, 0}, ++ {0x21, 0x23, 0x23, 0, 0}, ++ {0x22, 0x8, 0x8, 0, 0}, ++ {0x23, 0, 0, 0, 0}, ++ {0x24, 0, 0, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0x33, 0x33, 0, 0}, ++ {0x27, 0x55, 0x55, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x30, 0x30, 0, 0}, ++ {0x2A, 0xb, 0xb, 0, 0}, ++ {0x2B, 0x1b, 0x1b, 0, 0}, ++ {0x2C, 0x3, 0x3, 0, 0}, ++ {0x2D, 0x1b, 0x1b, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x20, 0x20, 0, 0}, ++ {0x30, 0xa, 0xa, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0x62, 0x62, 0, 0}, ++ {0x33, 0x19, 0x19, 0, 0}, ++ {0x34, 0x33, 0x33, 0, 0}, ++ {0x35, 0x77, 0x77, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x70, 0x70, 0, 0}, ++ {0x38, 0x3, 0x3, 0, 0}, ++ {0x39, 0xf, 0xf, 0, 0}, ++ {0x3A, 0x6, 0x6, 0, 0}, ++ {0x3B, 0xcf, 0xcf, 0, 0}, ++ {0x3C, 0x1a, 0x1a, 0, 0}, ++ {0x3D, 0x6, 0x6, 0, 0}, ++ {0x3E, 0x42, 0x42, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0xfb, 0xfb, 0, 0}, ++ {0x41, 0x9a, 0x9a, 0, 0}, ++ {0x42, 0x7a, 0x7a, 0, 0}, ++ {0x43, 0x29, 0x29, 0, 0}, ++ {0x44, 0, 0, 0, 0}, ++ {0x45, 0x8, 0x8, 0, 0}, ++ {0x46, 0xce, 0xce, 0, 0}, ++ {0x47, 0x27, 0x27, 0, 0}, ++ {0x48, 0x62, 0x62, 0, 0}, ++ {0x49, 0x6, 0x6, 0, 0}, ++ {0x4A, 0x58, 0x58, 0, 0}, ++ {0x4B, 0xf7, 0xf7, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0xb3, 0xb3, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0, 0, 0, 0}, ++ {0x51, 0x9, 0x9, 0, 0}, ++ {0x52, 0x5, 0x5, 0, 0}, ++ {0x53, 0x17, 0x17, 0, 0}, ++ {0x54, 0x38, 0x38, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0xb, 0xb, 0, 0}, ++ {0x58, 0, 0, 0, 0}, ++ {0x59, 0, 0, 0, 0}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0, 0, 0, 0}, ++ {0x5C, 0, 0, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x88, 0x88, 0, 0}, ++ {0x5F, 0xcc, 0xcc, 0, 0}, ++ {0x60, 0x74, 0x74, 0, 0}, ++ {0x61, 0x74, 0x74, 0, 0}, ++ {0x62, 0x74, 0x74, 0, 0}, ++ {0x63, 0x44, 0x44, 0, 0}, ++ {0x64, 0x77, 0x77, 0, 0}, ++ {0x65, 0x44, 0x44, 0, 0}, ++ {0x66, 0x77, 0x77, 0, 0}, ++ {0x67, 0x55, 0x55, 0, 0}, ++ {0x68, 0x77, 0x77, 0, 0}, ++ {0x69, 0x77, 0x77, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0x7f, 0x7f, 0, 0}, ++ {0x6C, 0x8, 0x8, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0x88, 0x88, 0, 0}, ++ {0x6F, 0x66, 0x66, 0, 0}, ++ {0x70, 0x66, 0x66, 0, 0}, ++ {0x71, 0x28, 0x28, 0, 0}, ++ {0x72, 0x55, 0x55, 0, 0}, ++ {0x73, 0x4, 0x4, 0, 0}, ++ {0x74, 0, 0, 0, 0}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0, 0, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0xd6, 0xd6, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0xb4, 0xb4, 0, 0}, ++ {0x84, 0x1, 0x1, 0, 0}, ++ {0x85, 0x20, 0x20, 0, 0}, ++ {0x86, 0x5, 0x5, 0, 0}, ++ {0x87, 0xff, 0xff, 0, 0}, ++ {0x88, 0x7, 0x7, 0, 0}, ++ {0x89, 0x77, 0x77, 0, 0}, ++ {0x8A, 0x77, 0x77, 0, 0}, ++ {0x8B, 0x77, 0x77, 0, 0}, ++ {0x8C, 0x77, 0x77, 0, 0}, ++ {0x8D, 0x8, 0x8, 0, 0}, ++ {0x8E, 0xa, 0xa, 0, 0}, ++ {0x8F, 0x8, 0x8, 0, 0}, ++ {0x90, 0x18, 0x18, 0, 0}, ++ {0x91, 0x5, 0x5, 0, 0}, ++ {0x92, 0x1f, 0x1f, 0, 0}, ++ {0x93, 0x10, 0x10, 0, 0}, ++ {0x94, 0x3, 0x3, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0xaa, 0xaa, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0x23, 0x23, 0, 0}, ++ {0x9A, 0x7, 0x7, 0, 0}, ++ {0x9B, 0xf, 0xf, 0, 0}, ++ {0x9C, 0x10, 0x10, 0, 0}, ++ {0x9D, 0x3, 0x3, 0, 0}, ++ {0x9E, 0x4, 0x4, 0, 0}, ++ {0x9F, 0x20, 0x20, 0, 0}, ++ {0xA0, 0, 0, 0, 0}, ++ {0xA1, 0, 0, 0, 0}, ++ {0xA2, 0, 0, 0, 0}, ++ {0xA3, 0, 0, 0, 0}, ++ {0xA4, 0x1, 0x1, 0, 0}, ++ {0xA5, 0x77, 0x77, 0, 0}, ++ {0xA6, 0x77, 0x77, 0, 0}, ++ {0xA7, 0x77, 0x77, 0, 0}, ++ {0xA8, 0x77, 0x77, 0, 0}, ++ {0xA9, 0x8c, 0x8c, 0, 0}, ++ {0xAA, 0x88, 0x88, 0, 0}, ++ {0xAB, 0x78, 0x78, 0, 0}, ++ {0xAC, 0x57, 0x57, 0, 0}, ++ {0xAD, 0x88, 0x88, 0, 0}, ++ {0xAE, 0, 0, 0, 0}, ++ {0xAF, 0x8, 0x8, 0, 0}, ++ {0xB0, 0x88, 0x88, 0, 0}, ++ {0xB1, 0, 0, 0, 0}, ++ {0xB2, 0x1b, 0x1b, 0, 0}, ++ {0xB3, 0x3, 0x3, 0, 0}, ++ {0xB4, 0x24, 0x24, 0, 0}, ++ {0xB5, 0x3, 0x3, 0, 0}, ++ {0xB6, 0x1b, 0x1b, 0, 0}, ++ {0xB7, 0x24, 0x24, 0, 0}, ++ {0xB8, 0x3, 0x3, 0, 0}, ++ {0xB9, 0, 0, 0, 0}, ++ {0xBA, 0xaa, 0xaa, 0, 0}, ++ {0xBB, 0, 0, 0, 0}, ++ {0xBC, 0x4, 0x4, 0, 0}, ++ {0xBD, 0, 0, 0, 0}, ++ {0xBE, 0x8, 0x8, 0, 0}, ++ {0xBF, 0x11, 0x11, 0, 0}, ++ {0xC0, 0, 0, 0, 0}, ++ {0xC1, 0, 0, 0, 0}, ++ {0xC2, 0x62, 0x62, 0, 0}, ++ {0xC3, 0x1e, 0x1e, 0, 0}, ++ {0xC4, 0x33, 0x33, 0, 0}, ++ {0xC5, 0x37, 0x37, 0, 0}, ++ {0xC6, 0, 0, 0, 0}, ++ {0xC7, 0x70, 0x70, 0, 0}, ++ {0xC8, 0x1e, 0x1e, 0, 0}, ++ {0xC9, 0x6, 0x6, 0, 0}, ++ {0xCA, 0x4, 0x4, 0, 0}, ++ {0xCB, 0x2f, 0x2f, 0, 0}, ++ {0xCC, 0xf, 0xf, 0, 0}, ++ {0xCD, 0, 0, 0, 0}, ++ {0xCE, 0xff, 0xff, 0, 0}, ++ {0xCF, 0x8, 0x8, 0, 0}, ++ {0xD0, 0x3f, 0x3f, 0, 0}, ++ {0xD1, 0x3f, 0x3f, 0, 0}, ++ {0xD2, 0x3f, 0x3f, 0, 0}, ++ {0xD3, 0, 0, 0, 0}, ++ {0xD4, 0, 0, 0, 0}, ++ {0xD5, 0, 0, 0, 0}, ++ {0xD6, 0xcc, 0xcc, 0, 0}, ++ {0xD7, 0, 0, 0, 0}, ++ {0xD8, 0x8, 0x8, 0, 0}, ++ {0xD9, 0x8, 0x8, 0, 0}, ++ {0xDA, 0x8, 0x8, 0, 0}, ++ {0xDB, 0x11, 0x11, 0, 0}, ++ {0xDC, 0, 0, 0, 0}, ++ {0xDD, 0x87, 0x87, 0, 0}, ++ {0xDE, 0x88, 0x88, 0, 0}, ++ {0xDF, 0x8, 0x8, 0, 0}, ++ {0xE0, 0x8, 0x8, 0, 0}, ++ {0xE1, 0x8, 0x8, 0, 0}, ++ {0xE2, 0, 0, 0, 0}, ++ {0xE3, 0, 0, 0, 0}, ++ {0xE4, 0, 0, 0, 0}, ++ {0xE5, 0xf5, 0xf5, 0, 0}, ++ {0xE6, 0x30, 0x30, 0, 0}, ++ {0xE7, 0x1, 0x1, 0, 0}, ++ {0xE8, 0, 0, 0, 0}, ++ {0xE9, 0xff, 0xff, 0, 0}, ++ {0xEA, 0, 0, 0, 0}, ++ {0xEB, 0, 0, 0, 0}, ++ {0xEC, 0x22, 0x22, 0, 0}, ++ {0xED, 0, 0, 0, 0}, ++ {0xEE, 0, 0, 0, 0}, ++ {0xEF, 0, 0, 0, 0}, ++ {0xF0, 0x3, 0x3, 0, 0}, ++ {0xF1, 0x1, 0x1, 0, 0}, ++ {0xF2, 0, 0, 0, 0}, ++ {0xF3, 0, 0, 0, 0}, ++ {0xF4, 0, 0, 0, 0}, ++ {0xF5, 0, 0, 0, 0}, ++ {0xF6, 0, 0, 0, 0}, ++ {0xF7, 0x6, 0x6, 0, 0}, ++ {0xF8, 0, 0, 0, 0}, ++ {0xF9, 0, 0, 0, 0}, ++ {0xFA, 0x40, 0x40, 0, 0}, ++ {0xFB, 0, 0, 0, 0}, ++ {0xFC, 0x1, 0x1, 0, 0}, ++ {0xFD, 0x80, 0x80, 0, 0}, ++ {0xFE, 0x2, 0x2, 0, 0}, ++ {0xFF, 0x10, 0x10, 0, 0}, ++ {0x100, 0x2, 0x2, 0, 0}, ++ {0x101, 0x1e, 0x1e, 0, 0}, ++ {0x102, 0x1e, 0x1e, 0, 0}, ++ {0x103, 0, 0, 0, 0}, ++ {0x104, 0x1f, 0x1f, 0, 0}, ++ {0x105, 0, 0x8, 0, 1}, ++ {0x106, 0x2a, 0x2a, 0, 0}, ++ {0x107, 0xf, 0xf, 0, 0}, ++ {0x108, 0, 0, 0, 0}, ++ {0x109, 0, 0, 0, 0}, ++ {0x10A, 0, 0, 0, 0}, ++ {0x10B, 0, 0, 0, 0}, ++ {0x10C, 0, 0, 0, 0}, ++ {0x10D, 0, 0, 0, 0}, ++ {0x10E, 0, 0, 0, 0}, ++ {0x10F, 0, 0, 0, 0}, ++ {0x110, 0, 0, 0, 0}, ++ {0x111, 0, 0, 0, 0}, ++ {0x112, 0, 0, 0, 0}, ++ {0x113, 0, 0, 0, 0}, ++ {0x114, 0, 0, 0, 0}, ++ {0x115, 0, 0, 0, 0}, ++ {0x116, 0, 0, 0, 0}, ++ {0x117, 0, 0, 0, 0}, ++ {0x118, 0, 0, 0, 0}, ++ {0x119, 0, 0, 0, 0}, ++ {0x11A, 0, 0, 0, 0}, ++ {0x11B, 0, 0, 0, 0}, ++ {0x11C, 0x1, 0x1, 0, 0}, ++ {0x11D, 0, 0, 0, 0}, ++ {0x11E, 0, 0, 0, 0}, ++ {0x11F, 0, 0, 0, 0}, ++ {0x120, 0, 0, 0, 0}, ++ {0x121, 0, 0, 0, 0}, ++ {0x122, 0x80, 0x80, 0, 0}, ++ {0x123, 0, 0, 0, 0}, ++ {0x124, 0xf8, 0xf8, 0, 0}, ++ {0x125, 0, 0, 0, 0}, ++ {0x126, 0, 0, 0, 0}, ++ {0x127, 0, 0, 0, 0}, ++ {0x128, 0, 0, 0, 0}, ++ {0x129, 0, 0, 0, 0}, ++ {0x12A, 0, 0, 0, 0}, ++ {0x12B, 0, 0, 0, 0}, ++ {0x12C, 0, 0, 0, 0}, ++ {0x12D, 0, 0, 0, 0}, ++ {0x12E, 0, 0, 0, 0}, ++ {0x12F, 0, 0, 0, 0}, ++ {0x130, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++#define LCNPHY_NUM_DIG_FILT_COEFFS 16 ++#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13 ++ ++static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK] ++ [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { ++ {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64, ++ 128, 64,}, ++ {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93, ++ 167, 93,}, ++ {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64, ++ 128, 64,}, ++ {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760, ++ 170, 340, 170,}, ++ {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760, ++ 256, 185, 256,}, ++ {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760, ++ 256, 273, 256,}, ++ {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760, ++ 256, 352, 256,}, ++ {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760, ++ 128, 233, 128,}, ++ {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256, ++ 1881, 256,}, ++ {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256, ++ 1881, 256,}, ++ {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128, ++ 384, 288,}, ++ {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864, ++ 128, 384, 288,}, ++ {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760, ++ 170, 340, 170,}, ++}; ++ ++#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3 ++static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM] ++ [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { ++ {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, ++ 0x278, 0xfea0, 0x80, 0x100, 0x80,}, ++ {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, ++ 750, 0xFE2B, 212, 0xFFCE, 212,}, ++ {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748, ++ 0xFEF2, 128, 0xFFE2, 128} ++}; ++ ++#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \ ++ mod_phy_reg(pi, 0x4a4, \ ++ (0x1ff << 0), \ ++ (u16)(idx) << 0) ++ ++#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \ ++ mod_phy_reg(pi, 0x4a5, \ ++ (0x7 << 8), \ ++ (u16)(npt) << 8) ++ ++#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \ ++ (read_phy_reg((pi), 0x4a4) & \ ++ ((0x1 << 15) | \ ++ (0x1 << 14) | \ ++ (0x1 << 13))) ++ ++#define wlc_lcnphy_get_tx_pwr_npt(pi) \ ++ ((read_phy_reg(pi, 0x4a5) & \ ++ (0x7 << 8)) >> \ ++ 8) ++ ++#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \ ++ (read_phy_reg(pi, 0x473) & 0x1ff) ++ ++#define wlc_lcnphy_get_target_tx_pwr(pi) \ ++ ((read_phy_reg(pi, 0x4a7) & \ ++ (0xff << 0)) >> \ ++ 0) ++ ++#define wlc_lcnphy_set_target_tx_pwr(pi, target) \ ++ mod_phy_reg(pi, 0x4a7, \ ++ (0xff << 0), \ ++ (u16)(target) << 0) ++ ++#define wlc_radio_2064_rcal_done(pi) \ ++ (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20)) ++ ++#define tempsense_done(pi) \ ++ (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000)) ++ ++#define LCNPHY_IQLOCC_READ(val) \ ++ ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f))) ++ ++#define FIXED_TXPWR 78 ++#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val)) ++ ++void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti) ++{ ++ wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456); ++} ++ ++void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti) ++{ ++ wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456); ++} ++ ++static void ++wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id, ++ const u16 *tbl_ptr, u32 tbl_len, ++ u32 tbl_width, u32 tbl_offset) ++{ ++ struct phytbl_info tab; ++ tab.tbl_id = tbl_id; ++ tab.tbl_ptr = tbl_ptr; ++ tab.tbl_len = tbl_len; ++ tab.tbl_width = tbl_width; ++ tab.tbl_offset = tbl_offset; ++ wlc_lcnphy_read_table(pi, &tab); ++} ++ ++static void ++wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id, ++ const u16 *tbl_ptr, u32 tbl_len, ++ u32 tbl_width, u32 tbl_offset) ++{ ++ ++ struct phytbl_info tab; ++ tab.tbl_id = tbl_id; ++ tab.tbl_ptr = tbl_ptr; ++ tab.tbl_len = tbl_len; ++ tab.tbl_width = tbl_width; ++ tab.tbl_offset = tbl_offset; ++ wlc_lcnphy_write_table(pi, &tab); ++} ++ ++static u32 ++wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) ++{ ++ u32 quotient, remainder, roundup, rbit; ++ ++ quotient = dividend / divisor; ++ remainder = dividend % divisor; ++ rbit = divisor & 1; ++ roundup = (divisor >> 1) + rbit; ++ ++ while (precision--) { ++ quotient <<= 1; ++ if (remainder >= roundup) { ++ quotient++; ++ remainder = ((remainder - roundup) << 1) + rbit; ++ } else { ++ remainder <<= 1; ++ } ++ } ++ ++ if (remainder >= roundup) ++ quotient++; ++ ++ return quotient; ++} ++ ++static int wlc_lcnphy_calc_floor(s16 coeff_x, int type) ++{ ++ int k; ++ k = 0; ++ if (type == 0) { ++ if (coeff_x < 0) ++ k = (coeff_x - 1) / 2; ++ else ++ k = coeff_x / 2; ++ } ++ ++ if (type == 1) { ++ if ((coeff_x + 1) < 0) ++ k = (coeff_x) / 2; ++ else ++ k = (coeff_x + 1) / 2; ++ } ++ return k; ++} ++ ++static void ++wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains) ++{ ++ u16 dac_gain, rfgain0, rfgain1; ++ ++ dac_gain = read_phy_reg(pi, 0x439) >> 0; ++ gains->dac_gain = (dac_gain & 0x380) >> 7; ++ ++ rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0; ++ rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0; ++ ++ gains->gm_gain = rfgain0 & 0xff; ++ gains->pga_gain = (rfgain0 >> 8) & 0xff; ++ gains->pad_gain = rfgain1 & 0xff; ++} ++ ++ ++static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain) ++{ ++ u16 dac_ctrl; ++ ++ dac_ctrl = (read_phy_reg(pi, 0x439) >> 0); ++ dac_ctrl = dac_ctrl & 0xc7f; ++ dac_ctrl = dac_ctrl | (dac_gain << 7); ++ mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0); ++ ++} ++ ++static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable) ++{ ++ u16 bit = bEnable ? 1 : 0; ++ ++ mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7); ++ ++ mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6); ++} ++ ++static void ++wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable) ++{ ++ u16 ebit = enable ? 1 : 0; ++ ++ mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0); ++ ++ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { ++ mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4); ++ mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6); ++ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); ++ mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6); ++ } else { ++ mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12); ++ mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13); ++ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10); ++ mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3); ++ } ++} ++ ++static void ++wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, ++ u16 trsw, ++ u16 ext_lna, ++ u16 biq2, ++ u16 biq1, ++ u16 tia, u16 lna2, u16 lna1) ++{ ++ u16 gain0_15, gain16_19; ++ ++ gain16_19 = biq2 & 0xf; ++ gain0_15 = ((biq1 & 0xf) << 12) | ++ ((tia & 0xf) << 8) | ++ ((lna2 & 0x3) << 6) | ++ ((lna2 & ++ 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); ++ ++ mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); ++ mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); ++ mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); ++ ++ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { ++ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); ++ mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); ++ } else { ++ mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10); ++ ++ mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15); ++ ++ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); ++ } ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); ++ ++} ++ ++static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx) ++{ ++ ++ mod_phy_reg(pi, 0x44d, ++ (0x1 << 1) | ++ (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0)); ++ ++ or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0)); ++} ++ ++static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi) ++{ ++ ++ and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0))); ++} ++ ++static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b) ++{ ++ mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0); ++ ++ mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0); ++ ++ mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0); ++ ++ mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0); ++ ++ mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0); ++ ++ mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0); ++ ++} ++ ++static bool ++wlc_lcnphy_rx_iq_est(struct brcms_phy *pi, ++ u16 num_samps, ++ u8 wait_time, struct lcnphy_iq_est *iq_est) ++{ ++ int wait_count = 0; ++ bool result = true; ++ u8 phybw40; ++ phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5); ++ ++ mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3); ++ ++ mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0); ++ ++ mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0); ++ ++ mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8); ++ ++ mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9); ++ ++ while (read_phy_reg(pi, 0x481) & (0x1 << 9)) { ++ ++ if (wait_count > (10 * 500)) { ++ result = false; ++ goto cleanup; ++ } ++ udelay(100); ++ wait_count++; ++ } ++ ++ iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) | ++ (u32) read_phy_reg(pi, 0x484); ++ iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) | ++ (u32) read_phy_reg(pi, 0x486); ++ iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) | ++ (u32) read_phy_reg(pi, 0x488); ++ ++cleanup: ++ mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5); ++ ++ return result; ++} ++ ++static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps) ++{ ++#define LCNPHY_MIN_RXIQ_PWR 2 ++ bool result; ++ u16 a0_new, b0_new; ++ struct lcnphy_iq_est iq_est = { 0, 0, 0 }; ++ s32 a, b, temp; ++ s16 iq_nbits, qq_nbits, arsh, brsh; ++ s32 iq; ++ u32 ii, qq; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0); ++ b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0); ++ mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6); ++ ++ wlc_lcnphy_set_rx_iq_comp(pi, 0, 0); ++ ++ result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est); ++ if (!result) ++ goto cleanup; ++ ++ iq = (s32) iq_est.iq_prod; ++ ii = iq_est.i_pwr; ++ qq = iq_est.q_pwr; ++ ++ if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) { ++ result = false; ++ goto cleanup; ++ } ++ ++ iq_nbits = wlc_phy_nbits(iq); ++ qq_nbits = wlc_phy_nbits(qq); ++ ++ arsh = 10 - (30 - iq_nbits); ++ if (arsh >= 0) { ++ a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); ++ temp = (s32) (ii >> arsh); ++ if (temp == 0) ++ return false; ++ } else { ++ a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); ++ temp = (s32) (ii << -arsh); ++ if (temp == 0) ++ return false; ++ } ++ a /= temp; ++ brsh = qq_nbits - 31 + 20; ++ if (brsh >= 0) { ++ b = (qq << (31 - qq_nbits)); ++ temp = (s32) (ii >> brsh); ++ if (temp == 0) ++ return false; ++ } else { ++ b = (qq << (31 - qq_nbits)); ++ temp = (s32) (ii << -brsh); ++ if (temp == 0) ++ return false; ++ } ++ b /= temp; ++ b -= a * a; ++ b = (s32) int_sqrt((unsigned long) b); ++ b -= (1 << 10); ++ a0_new = (u16) (a & 0x3ff); ++ b0_new = (u16) (b & 0x3ff); ++cleanup: ++ ++ wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new); ++ ++ mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3); ++ ++ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new; ++ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new; ++ ++ return result; ++} ++ ++static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) ++{ ++ struct lcnphy_iq_est iq_est = { 0, 0, 0 }; ++ ++ if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est)) ++ return 0; ++ return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; ++} ++ ++static bool ++wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, ++ const struct lcnphy_rx_iqcomp *iqcomp, ++ int iqcomp_sz, bool tx_switch, bool rx_switch, int module, ++ int tx_gain_idx) ++{ ++ struct lcnphy_txgains old_gains; ++ u16 tx_pwr_ctrl; ++ u8 tx_gain_index_old = 0; ++ bool result = false, tx_gain_override_old = false; ++ u16 i, Core1TxControl_old, RFOverride0_old, ++ RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, ++ rfoverride3_old, rfoverride3val_old, rfoverride4_old, ++ rfoverride4val_old, afectrlovr_old, afectrlovrval_old; ++ int tia_gain; ++ u32 received_power, rx_pwr_threshold; ++ u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; ++ u16 values_to_save[11]; ++ s16 *ptr; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); ++ if (NULL == ptr) ++ return false; ++ if (module == 2) { ++ while (iqcomp_sz--) { ++ if (iqcomp[iqcomp_sz].chan == ++ CHSPEC_CHANNEL(pi->radio_chanspec)) { ++ wlc_lcnphy_set_rx_iq_comp(pi, ++ (u16) ++ iqcomp[iqcomp_sz].a, ++ (u16) ++ iqcomp[iqcomp_sz].b); ++ result = true; ++ break; ++ } ++ } ++ goto cal_done; ++ } ++ ++ if (module == 1) { ++ ++ tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ ++ for (i = 0; i < 11; i++) ++ values_to_save[i] = ++ read_radio_reg(pi, rxiq_cal_rf_reg[i]); ++ Core1TxControl_old = read_phy_reg(pi, 0x631); ++ ++ or_phy_reg(pi, 0x631, 0x0015); ++ ++ RFOverride0_old = read_phy_reg(pi, 0x44c); ++ RFOverrideVal0_old = read_phy_reg(pi, 0x44d); ++ rfoverride2_old = read_phy_reg(pi, 0x4b0); ++ rfoverride2val_old = read_phy_reg(pi, 0x4b1); ++ rfoverride3_old = read_phy_reg(pi, 0x4f9); ++ rfoverride3val_old = read_phy_reg(pi, 0x4fa); ++ rfoverride4_old = read_phy_reg(pi, 0x938); ++ rfoverride4val_old = read_phy_reg(pi, 0x939); ++ afectrlovr_old = read_phy_reg(pi, 0x43b); ++ afectrlovrval_old = read_phy_reg(pi, 0x43c); ++ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); ++ old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); ++ ++ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); ++ if (tx_gain_override_old) { ++ wlc_lcnphy_get_tx_gain(pi, &old_gains); ++ tx_gain_index_old = pi_lcn->lcnphy_current_index; ++ } ++ ++ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); ++ ++ write_radio_reg(pi, RADIO_2064_REG116, 0x06); ++ write_radio_reg(pi, RADIO_2064_REG12C, 0x07); ++ write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); ++ write_radio_reg(pi, RADIO_2064_REG098, 0x03); ++ write_radio_reg(pi, RADIO_2064_REG00B, 0x7); ++ mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); ++ write_radio_reg(pi, RADIO_2064_REG01D, 0x01); ++ write_radio_reg(pi, RADIO_2064_REG114, 0x01); ++ write_radio_reg(pi, RADIO_2064_REG02E, 0x10); ++ write_radio_reg(pi, RADIO_2064_REG12A, 0x08); ++ ++ mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); ++ mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); ++ mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); ++ mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); ++ mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); ++ mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); ++ mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); ++ ++ wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); ++ write_phy_reg(pi, 0x6da, 0xffff); ++ or_phy_reg(pi, 0x6db, 0x3); ++ wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); ++ wlc_lcnphy_rx_gain_override_enable(pi, true); ++ ++ tia_gain = 8; ++ rx_pwr_threshold = 950; ++ while (tia_gain > 0) { ++ tia_gain -= 1; ++ wlc_lcnphy_set_rx_gain_by_distribution(pi, ++ 0, 0, 2, 2, ++ (u16) ++ tia_gain, 1, 0); ++ udelay(500); ++ ++ received_power = ++ wlc_lcnphy_measure_digital_power(pi, 2000); ++ if (received_power < rx_pwr_threshold) ++ break; ++ } ++ result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); ++ ++ wlc_lcnphy_stop_tx_tone(pi); ++ ++ write_phy_reg(pi, 0x631, Core1TxControl_old); ++ ++ write_phy_reg(pi, 0x44c, RFOverrideVal0_old); ++ write_phy_reg(pi, 0x44d, RFOverrideVal0_old); ++ write_phy_reg(pi, 0x4b0, rfoverride2_old); ++ write_phy_reg(pi, 0x4b1, rfoverride2val_old); ++ write_phy_reg(pi, 0x4f9, rfoverride3_old); ++ write_phy_reg(pi, 0x4fa, rfoverride3val_old); ++ write_phy_reg(pi, 0x938, rfoverride4_old); ++ write_phy_reg(pi, 0x939, rfoverride4val_old); ++ write_phy_reg(pi, 0x43b, afectrlovr_old); ++ write_phy_reg(pi, 0x43c, afectrlovrval_old); ++ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); ++ write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); ++ ++ wlc_lcnphy_clear_trsw_override(pi); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); ++ ++ for (i = 0; i < 11; i++) ++ write_radio_reg(pi, rxiq_cal_rf_reg[i], ++ values_to_save[i]); ++ ++ if (tx_gain_override_old) ++ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); ++ else ++ wlc_lcnphy_disable_tx_gain_override(pi); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); ++ wlc_lcnphy_rx_gain_override_enable(pi, false); ++ } ++ ++cal_done: ++ kfree(ptr); ++ return result; ++} ++ ++s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi) ++{ ++ s8 index; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ if (txpwrctrl_off(pi)) ++ index = pi_lcn->lcnphy_current_index; ++ else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) ++ index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on( ++ pi) / 2); ++ else ++ index = pi_lcn->lcnphy_current_index; ++ return index; ++} ++ ++void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel) ++{ ++ u16 afectrlovr, afectrlovrval; ++ afectrlovr = read_phy_reg(pi, 0x43b); ++ afectrlovrval = read_phy_reg(pi, 0x43c); ++ if (channel != 0) { ++ mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1); ++ ++ mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4); ++ ++ mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6); ++ ++ write_phy_reg(pi, 0x44b, 0xffff); ++ wlc_lcnphy_tx_pu(pi, 1); ++ ++ mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8); ++ ++ or_phy_reg(pi, 0x6da, 0x0080); ++ ++ or_phy_reg(pi, 0x00a, 0x228); ++ } else { ++ and_phy_reg(pi, 0x00a, ~(0x228)); ++ ++ and_phy_reg(pi, 0x6da, 0xFF7F); ++ write_phy_reg(pi, 0x43b, afectrlovr); ++ write_phy_reg(pi, 0x43c, afectrlovrval); ++ } ++} ++ ++static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi) ++{ ++ u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr; ++ ++ save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c); ++ save_AfeCtrlOvr = read_phy_reg(pi, 0x43b); ++ ++ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1); ++ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1); ++ ++ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe); ++ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe); ++ ++ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal); ++ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr); ++} ++ ++static void ++wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable) ++{ ++ if (enable) { ++ write_phy_reg(pi, 0x942, 0x7); ++ write_phy_reg(pi, 0x93b, ((1 << 13) + 23)); ++ write_phy_reg(pi, 0x93c, ((1 << 13) + 1989)); ++ ++ write_phy_reg(pi, 0x44a, 0x084); ++ write_phy_reg(pi, 0x44a, 0x080); ++ write_phy_reg(pi, 0x6d3, 0x2222); ++ write_phy_reg(pi, 0x6d3, 0x2220); ++ } else { ++ write_phy_reg(pi, 0x942, 0x0); ++ write_phy_reg(pi, 0x93b, ((0 << 13) + 23)); ++ write_phy_reg(pi, 0x93c, ((0 << 13) + 1989)); ++ } ++ wlapi_switch_macfreq(pi->sh->physhim, enable); ++} ++ ++static void ++wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec) ++{ ++ u8 channel = CHSPEC_CHANNEL(chanspec); ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ if (channel == 14) ++ mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); ++ else ++ mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); ++ ++ pi_lcn->lcnphy_bandedge_corr = 2; ++ if (channel == 1) ++ pi_lcn->lcnphy_bandedge_corr = 4; ++ ++ if (channel == 1 || channel == 2 || channel == 3 || ++ channel == 4 || channel == 9 || ++ channel == 10 || channel == 11 || channel == 12) { ++ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04); ++ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0); ++ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0); ++ ++ si_pmu_pllupd(pi->sh->sih); ++ write_phy_reg(pi, 0x942, 0); ++ wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); ++ pi_lcn->lcnphy_spurmod = 0; ++ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8); ++ ++ write_phy_reg(pi, 0x425, 0x5907); ++ } else { ++ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04); ++ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333); ++ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820); ++ ++ si_pmu_pllupd(pi->sh->sih); ++ write_phy_reg(pi, 0x942, 0); ++ wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); ++ ++ pi_lcn->lcnphy_spurmod = 0; ++ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8); ++ ++ write_phy_reg(pi, 0x425, 0x590a); ++ } ++ ++ or_phy_reg(pi, 0x44a, 0x44); ++ write_phy_reg(pi, 0x44a, 0x80); ++} ++ ++static void ++wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) ++{ ++ uint i; ++ const struct chan_info_2064_lcnphy *ci; ++ u8 rfpll_doubler = 0; ++ u8 pll_pwrup, pll_pwrup_ovr; ++ s32 qFxtal, qFref, qFvco, qFcal; ++ u8 d15, d16, f16, e44, e45; ++ u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div; ++ u16 loop_bw, d30, setCount; ++ ++ u8 h29, h28_ten, e30, h30_ten, cp_current; ++ u16 g30, d28; ++ ++ ci = &chan_info_2064_lcnphy[0]; ++ rfpll_doubler = 1; ++ ++ mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2); ++ ++ write_radio_reg(pi, RADIO_2064_REG09E, 0xf); ++ if (!rfpll_doubler) { ++ loop_bw = PLL_2064_LOOP_BW; ++ d30 = PLL_2064_D30; ++ } else { ++ loop_bw = PLL_2064_LOOP_BW_DOUBLER; ++ d30 = PLL_2064_D30_DOUBLER; ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++) ++ if (chan_info_2064_lcnphy[i].chan == channel) ++ break; ++ ++ if (i >= ARRAY_SIZE(chan_info_2064_lcnphy)) ++ return; ++ ++ ci = &chan_info_2064_lcnphy[i]; ++ } ++ ++ write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune); ++ ++ mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx); ++ ++ mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl); ++ ++ mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g); ++ ++ mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2, ++ (ci->logen_rccr_rx) << 2); ++ ++ mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune); ++ ++ mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4, ++ (ci->pa_rxrf_lna2_freq_tune) << 4); ++ ++ write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1); ++ ++ pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044); ++ pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B); ++ ++ or_radio_reg(pi, RADIO_2064_REG044, 0x07); ++ ++ or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1); ++ e44 = 0; ++ e45 = 0; ++ ++ fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq); ++ if (pi->xtalfreq > 26000000) ++ e44 = 1; ++ if (pi->xtalfreq > 52000000) ++ e45 = 1; ++ if (e44 == 0) ++ fcal_div = 1; ++ else if (e45 == 0) ++ fcal_div = 2; ++ else ++ fcal_div = 4; ++ fvco3 = (ci->freq * 3); ++ fref3 = 2 * fpfd; ++ ++ qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16); ++ qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16); ++ qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ; ++ qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16); ++ ++ write_radio_reg(pi, RADIO_2064_REG04F, 0x02); ++ ++ d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1; ++ write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2))); ++ write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5); ++ ++ d16 = (qFcal * 8 / (d15 + 1)) - 1; ++ write_radio_reg(pi, RADIO_2064_REG051, d16); ++ ++ f16 = ((d16 + 1) * (d15 + 1)) / qFcal; ++ setCount = f16 * 3 * (ci->freq) / 32 - 1; ++ mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0), ++ (u8) (setCount >> 8)); ++ ++ or_radio_reg(pi, RADIO_2064_REG053, 0x10); ++ write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff)); ++ ++ div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4; ++ ++ div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4; ++ while (div_frac >= fref3) { ++ div_int++; ++ div_frac -= fref3; ++ } ++ div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20); ++ ++ mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0), ++ (u8) (div_int >> 4)); ++ mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4), ++ (u8) (div_int << 4)); ++ mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0), ++ (u8) (div_frac >> 16)); ++ write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff); ++ write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff); ++ ++ write_radio_reg(pi, RADIO_2064_REG040, 0xfb); ++ ++ write_radio_reg(pi, RADIO_2064_REG041, 0x9A); ++ write_radio_reg(pi, RADIO_2064_REG042, 0xA3); ++ write_radio_reg(pi, RADIO_2064_REG043, 0x0C); ++ ++ h29 = LCN_BW_LMT / loop_bw; ++ d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) * ++ (fvco3 / 2 - PLL_2064_LOW_END_VCO)) / ++ (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO)) ++ + PLL_2064_LOW_END_KVCO; ++ h28_ten = (d28 * 10) / LCN_VCO_DIV; ++ e30 = (d30 - LCN_OFFSET) / LCN_FACT; ++ g30 = LCN_OFFSET + (e30 * LCN_FACT); ++ h30_ten = (g30 * 10) / LCN_CUR_DIV; ++ cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten; ++ mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current); ++ ++ if (channel >= 1 && channel <= 5) ++ write_radio_reg(pi, RADIO_2064_REG03C, 0x8); ++ else ++ write_radio_reg(pi, RADIO_2064_REG03C, 0x7); ++ write_radio_reg(pi, RADIO_2064_REG03D, 0x3); ++ ++ mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c); ++ udelay(1); ++ ++ wlc_2064_vco_cal(pi); ++ ++ write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup); ++ write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr); ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { ++ write_radio_reg(pi, RADIO_2064_REG038, 3); ++ write_radio_reg(pi, RADIO_2064_REG091, 7); ++ } ++} ++ ++static int ++wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type) ++{ ++ s16 filt_index = -1; ++ int j; ++ ++ u16 addr[] = { ++ 0x910, ++ 0x91e, ++ 0x91f, ++ 0x924, ++ 0x925, ++ 0x926, ++ 0x920, ++ 0x921, ++ 0x927, ++ 0x928, ++ 0x929, ++ 0x922, ++ 0x923, ++ 0x930, ++ 0x931, ++ 0x932 ++ }; ++ ++ u16 addr_ofdm[] = { ++ 0x90f, ++ 0x900, ++ 0x901, ++ 0x906, ++ 0x907, ++ 0x908, ++ 0x902, ++ 0x903, ++ 0x909, ++ 0x90a, ++ 0x90b, ++ 0x904, ++ 0x905, ++ 0x90c, ++ 0x90d, ++ 0x90e ++ }; ++ ++ if (!is_ofdm) { ++ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) { ++ if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) { ++ filt_index = (s16) j; ++ break; ++ } ++ } ++ ++ if (filt_index != -1) { ++ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, addr[j], ++ LCNPHY_txdigfiltcoeffs_cck ++ [filt_index][j + 1]); ++ } ++ } else { ++ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) { ++ if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) { ++ filt_index = (s16) j; ++ break; ++ } ++ } ++ ++ if (filt_index != -1) { ++ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, addr_ofdm[j], ++ LCNPHY_txdigfiltcoeffs_ofdm ++ [filt_index][j + 1]); ++ } ++ } ++ ++ return (filt_index != -1) ? 0 : -1; ++} ++ ++void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) ++{ ++ u8 channel = CHSPEC_CHANNEL(chanspec); ++ ++ wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); ++ ++ wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); ++ ++ or_phy_reg(pi, 0x44a, 0x44); ++ write_phy_reg(pi, 0x44a, 0x80); ++ ++ wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); ++ udelay(1000); ++ ++ wlc_lcnphy_toggle_afe_pwdn(pi); ++ ++ write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); ++ write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); ++ ++ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { ++ mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); ++ ++ wlc_lcnphy_load_tx_iir_filter(pi, false, 3); ++ } else { ++ mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); ++ ++ wlc_lcnphy_load_tx_iir_filter(pi, false, 2); ++ } ++ ++ wlc_lcnphy_load_tx_iir_filter(pi, true, 0); ++ ++ mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); ++ ++} ++ ++static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi) ++{ ++ u16 pa_gain; ++ ++ pa_gain = (read_phy_reg(pi, 0x4fb) & ++ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >> ++ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT; ++ ++ return pa_gain; ++} ++ ++static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi, ++ struct lcnphy_txgains *target_gains) ++{ ++ u16 pa_gain = wlc_lcnphy_get_pa_gain(pi); ++ ++ mod_phy_reg( ++ pi, 0x4b5, ++ (0xffff << 0), ++ ((target_gains->gm_gain) | ++ (target_gains->pga_gain << 8)) << ++ 0); ++ mod_phy_reg(pi, 0x4fb, ++ (0x7fff << 0), ++ ((target_gains->pad_gain) | (pa_gain << 8)) << 0); ++ ++ mod_phy_reg( ++ pi, 0x4fc, ++ (0xffff << 0), ++ ((target_gains->gm_gain) | ++ (target_gains->pga_gain << 8)) << ++ 0); ++ mod_phy_reg(pi, 0x4fd, ++ (0x7fff << 0), ++ ((target_gains->pad_gain) | (pa_gain << 8)) << 0); ++ ++ wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain); ++ ++ wlc_lcnphy_enable_tx_gain_override(pi); ++} ++ ++static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0) ++{ ++ u16 m0m1 = (u16) m0 << 8; ++ struct phytbl_info tab; ++ ++ tab.tbl_ptr = &m0m1; ++ tab.tbl_len = 1; ++ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; ++ tab.tbl_offset = 87; ++ tab.tbl_width = 16; ++ wlc_lcnphy_write_table(pi, &tab); ++} ++ ++static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi) ++{ ++ u32 data_buf[64]; ++ struct phytbl_info tab; ++ ++ memset(data_buf, 0, sizeof(data_buf)); ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = data_buf; ++ ++ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { ++ ++ tab.tbl_len = 30; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++ ++ tab.tbl_len = 64; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET; ++ wlc_lcnphy_write_table(pi, &tab); ++} ++ ++enum lcnphy_tssi_mode { ++ LCNPHY_TSSI_PRE_PA, ++ LCNPHY_TSSI_POST_PA, ++ LCNPHY_TSSI_EXT ++}; ++ ++static void ++wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) ++{ ++ mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0); ++ ++ mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6); ++ ++ if (LCNPHY_TSSI_POST_PA == pos) { ++ mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); ++ } else { ++ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); ++ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); ++ } ++ } else { ++ mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); ++ ++ mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); ++ } else { ++ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); ++ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); ++ } ++ } ++ mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14); ++ ++ if (LCNPHY_TSSI_EXT == pos) { ++ write_radio_reg(pi, RADIO_2064_REG07F, 1); ++ mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2); ++ mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7); ++ mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3); ++ } ++} ++ ++static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi) ++{ ++ u16 N1, N2, N3, N4, N5, N6, N; ++ N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0)) ++ >> 0); ++ N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12)) ++ >> 12); ++ N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0)) ++ >> 0); ++ N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8)) ++ >> 8); ++ N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0)) ++ >> 0); ++ N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8)) ++ >> 8); ++ N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80; ++ if (N < 1600) ++ N = 1600; ++ return N; ++} ++ ++static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) ++{ ++ u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ auxpga_vmid = (2 << 8) | ++ (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf; ++ auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4; ++ auxpga_gain_temp = 2; ++ ++ mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1); ++ ++ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3); ++ ++ mod_phy_reg(pi, 0x4db, ++ (0x3ff << 0) | ++ (0x7 << 12), ++ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); ++ ++ mod_phy_reg(pi, 0x4dc, ++ (0x3ff << 0) | ++ (0x7 << 12), ++ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); ++ ++ mod_phy_reg(pi, 0x40a, ++ (0x3ff << 0) | ++ (0x7 << 12), ++ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); ++ ++ mod_phy_reg(pi, 0x40b, ++ (0x3ff << 0) | ++ (0x7 << 12), ++ (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); ++ ++ mod_phy_reg(pi, 0x40c, ++ (0x3ff << 0) | ++ (0x7 << 12), ++ (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); ++ ++ mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); ++} ++ ++static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) ++{ ++ struct phytbl_info tab; ++ u32 rfseq, ind; ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = &ind; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 0; ++ for (ind = 0; ind < 128; ind++) { ++ wlc_lcnphy_write_table(pi, &tab); ++ tab.tbl_offset++; ++ } ++ tab.tbl_offset = 704; ++ for (ind = 0; ind < 128; ind++) { ++ wlc_lcnphy_write_table(pi, &tab); ++ tab.tbl_offset++; ++ } ++ mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); ++ ++ wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); ++ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); ++ ++ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0); ++ ++ mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); ++ ++ mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); ++ ++ mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); ++ ++ mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); ++ ++ mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8); ++ ++ mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); ++ ++ mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8); ++ ++ mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6); ++ ++ mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0); ++ ++ wlc_lcnphy_clear_tx_power_offsets(pi); ++ ++ mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); ++ ++ mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0); ++ ++ mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); ++ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); ++ } else { ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); ++ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); ++ } ++ ++ write_radio_reg(pi, RADIO_2064_REG025, 0xc); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); ++ } else { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); ++ else ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1); ++ } ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); ++ else ++ mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2); ++ ++ mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0); ++ ++ mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3); ++ ++ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ mod_phy_reg(pi, 0x4d7, ++ (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12); ++ ++ rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); ++ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = &rfseq; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 6; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); ++ ++ mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); ++ ++ wlc_lcnphy_pwrctrl_rssiparams(pi); ++} ++ ++void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi) ++{ ++ u16 tx_cnt, tx_total, npt; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ tx_total = wlc_lcnphy_total_tx_frames(pi); ++ tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt; ++ npt = wlc_lcnphy_get_tx_pwr_npt(pi); ++ ++ if (tx_cnt > (1 << npt)) { ++ ++ pi_lcn->lcnphy_tssi_tx_cnt = tx_total; ++ ++ pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi); ++ pi_lcn->lcnphy_tssi_npt = npt; ++ ++ } ++} ++ ++s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1) ++{ ++ s32 a, b, p; ++ ++ a = 32768 + (a1 * tssi); ++ b = (1024 * b0) + (64 * b1 * tssi); ++ p = ((2 * b) + a) / (2 * a); ++ ++ return p; ++} ++ ++static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi) ++{ ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ return; ++ ++ pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313; ++ pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT; ++} ++ ++void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi) ++{ ++ struct phytbl_info tab; ++ u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM + ++ BRCMS_NUM_RATES_MCS_1_STREAM]; ++ uint i, j; ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ return; ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) { ++ ++ if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM) ++ j = TXP_FIRST_MCS_20_SISO; ++ ++ rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j])); ++ } ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_len = ARRAY_SIZE(rate_table); ++ tab.tbl_ptr = rate_table; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) { ++ wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min); ++ ++ wlc_lcnphy_txpower_reset_npt(pi); ++ } ++} ++ ++static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index) ++{ ++ u32 cck_offset[4] = { 22, 22, 22, 22 }; ++ u32 ofdm_offset, reg_offset_cck; ++ int i; ++ u16 index2; ++ struct phytbl_info tab; ++ ++ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) ++ return; ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14); ++ ++ or_phy_reg(pi, 0x6da, 0x0040); ++ ++ reg_offset_cck = 0; ++ for (i = 0; i < 4; i++) ++ cck_offset[i] -= reg_offset_cck; ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_len = 4; ++ tab.tbl_ptr = cck_offset; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; ++ wlc_lcnphy_write_table(pi, &tab); ++ ofdm_offset = 0; ++ tab.tbl_len = 1; ++ tab.tbl_ptr = &ofdm_offset; ++ for (i = 836; i < 862; i++) { ++ tab.tbl_offset = i; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13); ++ ++ mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6); ++ ++ mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15); ++ ++ index2 = (u16) (index * 2); ++ mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); ++ ++ mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4); ++ ++} ++ ++static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi) ++{ ++ s8 index, delta_brd, delta_temp, new_index, tempcorrx; ++ s16 manp, meas_temp, temp_diff; ++ bool neg = 0; ++ u16 temp; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) ++ return pi_lcn->lcnphy_current_index; ++ ++ index = FIXED_TXPWR; ++ ++ if (pi_lcn->lcnphy_tempsense_slope == 0) ++ return index; ++ ++ temp = (u16) wlc_lcnphy_tempsense(pi, 0); ++ meas_temp = LCNPHY_TEMPSENSE(temp); ++ ++ if (pi->tx_power_min != 0) ++ delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min); ++ else ++ delta_brd = 0; ++ ++ manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense); ++ temp_diff = manp - meas_temp; ++ if (temp_diff < 0) { ++ neg = 1; ++ temp_diff = -temp_diff; ++ } ++ ++ delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192), ++ (u32) (pi_lcn-> ++ lcnphy_tempsense_slope ++ * 10), 0); ++ if (neg) ++ delta_temp = -delta_temp; ++ ++ if (pi_lcn->lcnphy_tempsense_option == 3 ++ && LCNREV_IS(pi->pubpi.phy_rev, 0)) ++ delta_temp = 0; ++ if (pi_lcn->lcnphy_tempcorrx > 31) ++ tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64); ++ else ++ tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx; ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) ++ tempcorrx = 4; ++ new_index = ++ index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr; ++ new_index += tempcorrx; ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) ++ index = 127; ++ ++ if (new_index < 0 || new_index > 126) ++ return index; ++ ++ return new_index; ++} ++ ++static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode) ++{ ++ ++ u16 current_mode = mode; ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && ++ mode == LCNPHY_TX_PWR_CTRL_HW) ++ current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED; ++ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && ++ mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) ++ current_mode = LCNPHY_TX_PWR_CTRL_HW; ++ return current_mode; ++} ++ ++void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode) ++{ ++ u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ s8 index; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode); ++ old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 6), ++ ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6); ++ ++ mod_phy_reg(pi, 0x6a3, (0x1 << 4), ++ ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4); ++ ++ if (old_mode != mode) { ++ if (LCNPHY_TX_PWR_CTRL_HW == old_mode) { ++ ++ wlc_lcnphy_tx_pwr_update_npt(pi); ++ ++ wlc_lcnphy_clear_tx_power_offsets(pi); ++ } ++ if (LCNPHY_TX_PWR_CTRL_HW == mode) { ++ ++ wlc_lcnphy_txpower_recalc_target(pi); ++ ++ wlc_lcnphy_set_start_tx_pwr_idx(pi, ++ pi_lcn-> ++ lcnphy_tssi_idx); ++ wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt); ++ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0); ++ ++ pi_lcn->lcnphy_tssi_tx_cnt = ++ wlc_lcnphy_total_tx_frames(pi); ++ ++ wlc_lcnphy_disable_tx_gain_override(pi); ++ pi_lcn->lcnphy_tx_power_idx_override = -1; ++ } else ++ wlc_lcnphy_enable_tx_gain_override(pi); ++ ++ mod_phy_reg(pi, 0x4a4, ++ ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode); ++ if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) { ++ index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); ++ wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index); ++ pi_lcn->lcnphy_current_index = (s8) ++ ((read_phy_reg(pi, ++ 0x4a9) & ++ 0xFF) / 2); ++ } ++ } ++} ++ ++static void ++wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save) ++{ ++ u16 vmid; ++ int i; ++ for (i = 0; i < 20; i++) ++ values_to_save[i] = ++ read_radio_reg(pi, iqlo_loopback_rf_regs[i]); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); ++ mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11); ++ mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) ++ and_radio_reg(pi, RADIO_2064_REG03A, 0xFD); ++ else ++ and_radio_reg(pi, RADIO_2064_REG03A, 0xF9); ++ or_radio_reg(pi, RADIO_2064_REG11A, 0x1); ++ ++ or_radio_reg(pi, RADIO_2064_REG036, 0x01); ++ or_radio_reg(pi, RADIO_2064_REG11A, 0x18); ++ udelay(20); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); ++ else ++ or_radio_reg(pi, RADIO_2064_REG03A, 1); ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1); ++ else ++ or_radio_reg(pi, RADIO_2064_REG03A, 0x3); ++ } ++ ++ udelay(20); ++ ++ write_radio_reg(pi, RADIO_2064_REG025, 0xF); ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4); ++ else ++ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6); ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1); ++ else ++ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1); ++ } ++ ++ udelay(20); ++ ++ write_radio_reg(pi, RADIO_2064_REG005, 0x8); ++ or_radio_reg(pi, RADIO_2064_REG112, 0x80); ++ udelay(20); ++ ++ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); ++ or_radio_reg(pi, RADIO_2064_REG11F, 0x44); ++ udelay(20); ++ ++ or_radio_reg(pi, RADIO_2064_REG00B, 0x7); ++ or_radio_reg(pi, RADIO_2064_REG113, 0x10); ++ udelay(20); ++ ++ write_radio_reg(pi, RADIO_2064_REG007, 0x1); ++ udelay(20); ++ ++ vmid = 0x2A6; ++ mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3); ++ write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff)); ++ or_radio_reg(pi, RADIO_2064_REG11F, 0x44); ++ udelay(20); ++ ++ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); ++ udelay(20); ++ write_radio_reg(pi, RADIO_2064_REG012, 0x02); ++ or_radio_reg(pi, RADIO_2064_REG112, 0x06); ++ write_radio_reg(pi, RADIO_2064_REG036, 0x11); ++ write_radio_reg(pi, RADIO_2064_REG059, 0xcc); ++ write_radio_reg(pi, RADIO_2064_REG05C, 0x2e); ++ write_radio_reg(pi, RADIO_2064_REG078, 0xd7); ++ write_radio_reg(pi, RADIO_2064_REG092, 0x15); ++} ++ ++static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi) ++{ ++ uint delay_count = 0; ++ ++ while (wlc_lcnphy_iqcal_active(pi)) { ++ udelay(100); ++ delay_count++; ++ ++ if (delay_count > (10 * 500)) ++ break; ++ } ++ ++ return (0 == wlc_lcnphy_iqcal_active(pi)); ++} ++ ++static void ++wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save) ++{ ++ int i; ++ ++ and_phy_reg(pi, 0x44c, 0x0 >> 11); ++ ++ and_phy_reg(pi, 0x43b, 0xC); ++ ++ for (i = 0; i < 20; i++) ++ write_radio_reg(pi, iqlo_loopback_rf_regs[i], ++ values_to_save[i]); ++} ++ ++static void ++wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi, ++ struct lcnphy_txgains *target_gains, ++ enum lcnphy_cal_mode cal_mode, bool keep_tone) ++{ ++ ++ struct lcnphy_txgains cal_gains, temp_gains; ++ u16 hash; ++ u8 band_idx; ++ int j; ++ u16 ncorr_override[5]; ++ u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; ++ ++ u16 commands_fullcal[] = { ++ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 ++ }; ++ ++ u16 commands_recal[] = { ++ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 ++ }; ++ ++ u16 command_nums_fullcal[] = { ++ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 ++ }; ++ ++ u16 command_nums_recal[] = { ++ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 ++ }; ++ u16 *command_nums = command_nums_fullcal; ++ ++ u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start; ++ u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2; ++ u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl; ++ bool tx_gain_override_old; ++ struct lcnphy_txgains old_gains; ++ uint i, n_cal_cmds = 0, n_cal_start = 0; ++ u16 *values_to_save; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); ++ if (NULL == values_to_save) ++ return; ++ ++ save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); ++ save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); ++ ++ or_phy_reg(pi, 0x6da, 0x40); ++ or_phy_reg(pi, 0x6db, 0x3); ++ ++ switch (cal_mode) { ++ case LCNPHY_CAL_FULL: ++ start_coeffs = syst_coeffs; ++ cal_cmds = commands_fullcal; ++ n_cal_cmds = ARRAY_SIZE(commands_fullcal); ++ break; ++ ++ case LCNPHY_CAL_RECAL: ++ start_coeffs = syst_coeffs; ++ cal_cmds = commands_recal; ++ n_cal_cmds = ARRAY_SIZE(commands_recal); ++ command_nums = command_nums_recal; ++ break; ++ ++ default: ++ break; ++ } ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ start_coeffs, 11, 16, 64); ++ ++ write_phy_reg(pi, 0x6da, 0xffff); ++ mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3); ++ ++ tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ ++ save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db); ++ ++ mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0); ++ ++ mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12); ++ ++ wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save); ++ ++ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); ++ if (tx_gain_override_old) ++ wlc_lcnphy_get_tx_gain(pi, &old_gains); ++ ++ if (!target_gains) { ++ if (!tx_gain_override_old) ++ wlc_lcnphy_set_tx_pwr_by_index(pi, ++ pi_lcn->lcnphy_tssi_idx); ++ wlc_lcnphy_get_tx_gain(pi, &temp_gains); ++ target_gains = &temp_gains; ++ } ++ ++ hash = (target_gains->gm_gain << 8) | ++ (target_gains->pga_gain << 4) | (target_gains->pad_gain); ++ ++ band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0); ++ ++ cal_gains = *target_gains; ++ memset(ncorr_override, 0, sizeof(ncorr_override)); ++ for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) { ++ if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) { ++ cal_gains.gm_gain = ++ tbl_iqcal_gainparams_lcnphy[band_idx][j][1]; ++ cal_gains.pga_gain = ++ tbl_iqcal_gainparams_lcnphy[band_idx][j][2]; ++ cal_gains.pad_gain = ++ tbl_iqcal_gainparams_lcnphy[band_idx][j][3]; ++ memcpy(ncorr_override, ++ &tbl_iqcal_gainparams_lcnphy[band_idx][j][3], ++ sizeof(ncorr_override)); ++ break; ++ } ++ } ++ ++ wlc_lcnphy_set_tx_gain(pi, &cal_gains); ++ ++ write_phy_reg(pi, 0x453, 0xaa9); ++ write_phy_reg(pi, 0x93d, 0xc0); ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ lcnphy_iqcal_loft_gainladder, ++ ARRAY_SIZE(lcnphy_iqcal_loft_gainladder), ++ 16, 0); ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ lcnphy_iqcal_ir_gainladder, ++ ARRAY_SIZE( ++ lcnphy_iqcal_ir_gainladder), 16, ++ 32); ++ ++ if (pi->phy_tx_tone_freq) { ++ ++ wlc_lcnphy_stop_tx_tone(pi); ++ udelay(5); ++ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); ++ } else { ++ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); ++ } ++ ++ write_phy_reg(pi, 0x6da, 0xffff); ++ ++ for (i = n_cal_start; i < n_cal_cmds; i++) { ++ u16 zero_diq = 0; ++ u16 best_coeffs[11]; ++ u16 command_num; ++ ++ cal_type = (cal_cmds[i] & 0x0f00) >> 8; ++ ++ command_num = command_nums[i]; ++ if (ncorr_override[cal_type]) ++ command_num = ++ ncorr_override[cal_type] << 8 | (command_num & ++ 0xff); ++ ++ write_phy_reg(pi, 0x452, command_num); ++ ++ if ((cal_type == 3) || (cal_type == 4)) { ++ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ &diq_start, 1, 16, 69); ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ &zero_diq, 1, 16, 69); ++ } ++ ++ write_phy_reg(pi, 0x451, cal_cmds[i]); ++ ++ if (!wlc_lcnphy_iqcal_wait(pi)) ++ goto cleanup; ++ ++ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ best_coeffs, ++ ARRAY_SIZE(best_coeffs), 16, 96); ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ best_coeffs, ++ ARRAY_SIZE(best_coeffs), 16, 64); ++ ++ if ((cal_type == 3) || (cal_type == 4)) ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ &diq_start, 1, 16, 69); ++ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ pi_lcn->lcnphy_cal_results. ++ txiqlocal_bestcoeffs, ++ ARRAY_SIZE(pi_lcn-> ++ lcnphy_cal_results. ++ txiqlocal_bestcoeffs), ++ 16, 96); ++ } ++ ++ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ pi_lcn->lcnphy_cal_results. ++ txiqlocal_bestcoeffs, ++ ARRAY_SIZE(pi_lcn->lcnphy_cal_results. ++ txiqlocal_bestcoeffs), 16, 96); ++ pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true; ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ &pi_lcn->lcnphy_cal_results. ++ txiqlocal_bestcoeffs[0], 4, 16, 80); ++ ++ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, ++ &pi_lcn->lcnphy_cal_results. ++ txiqlocal_bestcoeffs[5], 2, 16, 85); ++ ++cleanup: ++ wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save); ++ kfree(values_to_save); ++ ++ if (!keep_tone) ++ wlc_lcnphy_stop_tx_tone(pi); ++ ++ write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2); ++ ++ write_phy_reg(pi, 0x453, 0); ++ ++ if (tx_gain_override_old) ++ wlc_lcnphy_set_tx_gain(pi, &old_gains); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old); ++ ++ write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl); ++ write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl); ++ ++} ++ ++static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) ++{ ++ bool suspend, tx_gain_override_old; ++ struct lcnphy_txgains old_gains; ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB, ++ idleTssi0_regvalue_2C; ++ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112); ++ u16 SAVE_jtag_bb_afe_switch = ++ read_radio_reg(pi, RADIO_2064_REG007) & 1; ++ u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; ++ u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; ++ idleTssi = read_phy_reg(pi, 0x4ab); ++ suspend = ++ (0 == ++ (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) & ++ MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ ++ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); ++ wlc_lcnphy_get_tx_gain(pi, &old_gains); ++ ++ wlc_lcnphy_enable_tx_gain_override(pi); ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 127); ++ write_radio_reg(pi, RADIO_2064_REG112, 0x6); ++ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1); ++ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); ++ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); ++ wlc_lcnphy_tssi_setup(pi); ++ wlc_phy_do_dummy_tx(pi, true, OFF); ++ idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) ++ >> 0); ++ ++ idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0)) ++ >> 0); ++ ++ if (idleTssi0_2C >= 256) ++ idleTssi0_OB = idleTssi0_2C - 256; ++ else ++ idleTssi0_OB = idleTssi0_2C + 256; ++ ++ idleTssi0_regvalue_OB = idleTssi0_OB; ++ if (idleTssi0_regvalue_OB >= 256) ++ idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256; ++ else ++ idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256; ++ mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); ++ ++ wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); ++ wlc_lcnphy_set_tx_gain(pi, &old_gains); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); ++ ++ write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain); ++ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch); ++ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga); ++ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en); ++ mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7); ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode) ++{ ++ bool suspend; ++ u16 save_txpwrCtrlEn; ++ u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain; ++ u16 auxpga_vmid; ++ struct phytbl_info tab; ++ u32 val; ++ u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025, ++ save_reg112; ++ u16 values_to_save[14]; ++ s8 index; ++ int i; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ udelay(999); ++ ++ save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007); ++ save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF); ++ save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F); ++ save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005); ++ save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025); ++ save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112); ++ ++ for (i = 0; i < 14; i++) ++ values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]); ++ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ index = pi_lcn->lcnphy_current_index; ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 127); ++ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1); ++ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4); ++ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2); ++ mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15); ++ ++ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); ++ ++ mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); ++ ++ mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); ++ ++ mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); ++ ++ mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); ++ ++ mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8); ++ ++ mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); ++ ++ mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8); ++ ++ mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4); ++ ++ mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8); ++ ++ mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12); ++ ++ mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12); ++ ++ mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13); ++ ++ mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); ++ ++ write_radio_reg(pi, RADIO_2064_REG025, 0xC); ++ ++ mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3); ++ ++ mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); ++ ++ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); ++ ++ val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); ++ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; ++ tab.tbl_width = 16; ++ tab.tbl_len = 1; ++ tab.tbl_ptr = &val; ++ tab.tbl_offset = 6; ++ wlc_lcnphy_write_table(pi, &tab); ++ if (mode == TEMPSENSE) { ++ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); ++ ++ mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12); ++ ++ auxpga_vmidcourse = 8; ++ auxpga_vmidfine = 0x4; ++ auxpga_gain = 2; ++ mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5); ++ } else { ++ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); ++ ++ mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12); ++ ++ auxpga_vmidcourse = 7; ++ auxpga_vmidfine = 0xa; ++ auxpga_gain = 2; ++ } ++ auxpga_vmid = ++ (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine); ++ mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2); ++ ++ mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1); ++ ++ mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12); ++ ++ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5); ++ ++ write_radio_reg(pi, RADIO_2064_REG112, 0x6); ++ ++ wlc_phy_do_dummy_tx(pi, true, OFF); ++ if (!tempsense_done(pi)) ++ udelay(10); ++ ++ write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007); ++ write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF); ++ write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F); ++ write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005); ++ write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025); ++ write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112); ++ for (i = 0; i < 14; i++) ++ write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]); ++ wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index); ++ ++ write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn); ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ udelay(999); ++} ++ ++static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) ++{ ++ struct lcnphy_txgains tx_gains; ++ u8 bbmult; ++ struct phytbl_info tab; ++ s32 a1, b0, b1; ++ s32 tssi, pwr, maxtargetpwr, mintargetpwr; ++ bool suspend; ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ ++ suspend = ++ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ if (!pi->hwpwrctrl_capable) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ tx_gains.gm_gain = 4; ++ tx_gains.pga_gain = 12; ++ tx_gains.pad_gain = 12; ++ tx_gains.dac_gain = 0; ++ ++ bbmult = 150; ++ } else { ++ tx_gains.gm_gain = 7; ++ tx_gains.pga_gain = 15; ++ tx_gains.pad_gain = 14; ++ tx_gains.dac_gain = 0; ++ ++ bbmult = 150; ++ } ++ wlc_lcnphy_set_tx_gain(pi, &tx_gains); ++ wlc_lcnphy_set_bbmult(pi, bbmult); ++ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); ++ } else { ++ ++ wlc_lcnphy_idle_tssi_est(ppi); ++ ++ wlc_lcnphy_clear_tx_power_offsets(pi); ++ ++ b0 = pi->txpa_2g[0]; ++ b1 = pi->txpa_2g[1]; ++ a1 = pi->txpa_2g[2]; ++ maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); ++ mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = &pwr; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 0; ++ for (tssi = 0; tssi < 128; tssi++) { ++ pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); ++ ++ pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; ++ wlc_lcnphy_write_table(pi, &tab); ++ tab.tbl_offset++; ++ } ++ ++ mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); ++ ++ write_phy_reg(pi, 0x4a8, 10); ++ ++ wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); ++ } ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) ++{ ++ u16 m0m1; ++ struct phytbl_info tab; ++ ++ tab.tbl_ptr = &m0m1; ++ tab.tbl_len = 1; ++ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; ++ tab.tbl_offset = 87; ++ tab.tbl_width = 16; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ return (u8) ((m0m1 & 0xff00) >> 8); ++} ++ ++static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain) ++{ ++ mod_phy_reg(pi, 0x4fb, ++ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK, ++ gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT); ++ mod_phy_reg(pi, 0x4fd, ++ LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK, ++ gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT); ++} ++ ++void ++wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, ++ u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0) ++{ ++ *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089)); ++ *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A)); ++ *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B)); ++ *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C)); ++} ++ ++void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b) ++{ ++ struct phytbl_info tab; ++ u16 iqcc[2]; ++ ++ iqcc[0] = a; ++ iqcc[1] = b; ++ ++ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = iqcc; ++ tab.tbl_len = 2; ++ tab.tbl_offset = 80; ++ wlc_lcnphy_write_table(pi, &tab); ++} ++ ++void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq) ++{ ++ struct phytbl_info tab; ++ ++ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = &didq; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 85; ++ wlc_lcnphy_write_table(pi, &tab); ++} ++ ++void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index) ++{ ++ struct phytbl_info tab; ++ u16 a, b; ++ u8 bb_mult; ++ u32 bbmultiqcomp, txgain, locoeffs, rfpower; ++ struct lcnphy_txgains gains; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ pi_lcn->lcnphy_tx_power_idx_override = (s8) index; ++ pi_lcn->lcnphy_current_index = (u8) index; ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_len = 1; ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; ++ tab.tbl_ptr = &bbmultiqcomp; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = &txgain; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ gains.gm_gain = (u16) (txgain & 0xff); ++ gains.pga_gain = (u16) (txgain >> 8) & 0xff; ++ gains.pad_gain = (u16) (txgain >> 16) & 0xff; ++ gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07; ++ wlc_lcnphy_set_tx_gain(pi, &gains); ++ wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f); ++ ++ bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff); ++ wlc_lcnphy_set_bbmult(pi, bb_mult); ++ ++ wlc_lcnphy_enable_tx_gain_override(pi); ++ ++ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { ++ ++ a = (u16) ((bbmultiqcomp >> 10) & 0x3ff); ++ b = (u16) (bbmultiqcomp & 0x3ff); ++ wlc_lcnphy_set_tx_iqcc(pi, a, b); ++ ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index; ++ tab.tbl_ptr = &locoeffs; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs); ++ ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; ++ tab.tbl_ptr = &rfpower; ++ wlc_lcnphy_read_table(pi, &tab); ++ mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0); ++ ++ } ++} ++ ++static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi) ++{ ++ u32 j; ++ struct phytbl_info tab; ++ u32 temp_offset[128]; ++ tab.tbl_ptr = temp_offset; ++ tab.tbl_len = 128; ++ tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL; ++ tab.tbl_width = 32; ++ tab.tbl_offset = 0; ++ ++ memset(temp_offset, 0, sizeof(temp_offset)); ++ for (j = 1; j < 128; j += 2) ++ temp_offset[j] = 0x80000; ++ ++ wlc_lcnphy_write_table(pi, &tab); ++ return; ++} ++ ++void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable) ++{ ++ if (!bEnable) { ++ ++ and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4))); ++ ++ mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1); ++ ++ and_phy_reg(pi, 0x44c, ++ ~(u16) ((0x1 << 3) | ++ (0x1 << 5) | ++ (0x1 << 12) | ++ (0x1 << 0) | (0x1 << 1) | (0x1 << 2))); ++ ++ and_phy_reg(pi, 0x44d, ++ ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14))); ++ mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2); ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0)); ++ ++ and_phy_reg(pi, 0x4f9, ++ ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); ++ ++ and_phy_reg(pi, 0x4fa, ++ ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); ++ } else { ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); ++ ++ mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4); ++ mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); ++ mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); ++ ++ wlc_lcnphy_set_trsw_override(pi, true, false); ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2); ++ mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); ++ mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); ++ mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0); ++ } else { ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); ++ mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3); ++ ++ mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); ++ mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2); ++ ++ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); ++ } ++ } ++} ++ ++static void ++wlc_lcnphy_run_samples(struct brcms_phy *pi, ++ u16 num_samps, ++ u16 num_loops, u16 wait, bool iqcalmode) ++{ ++ ++ or_phy_reg(pi, 0x6da, 0x8080); ++ ++ mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0); ++ if (num_loops != 0xffff) ++ num_loops--; ++ mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0); ++ ++ mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0); ++ ++ if (iqcalmode) { ++ ++ and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15)); ++ or_phy_reg(pi, 0x453, (0x1 << 15)); ++ } else { ++ write_phy_reg(pi, 0x63f, 1); ++ wlc_lcnphy_tx_pu(pi, 1); ++ } ++ ++ or_radio_reg(pi, RADIO_2064_REG112, 0x6); ++} ++ ++void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode) ++{ ++ ++ u8 phybw40; ++ phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ ++ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { ++ mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); ++ mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); ++ } else { ++ mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); ++ mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); ++ } ++ ++ if (phybw40 == 0) { ++ mod_phy_reg((pi), 0x410, ++ (0x1 << 6) | ++ (0x1 << 5), ++ ((CHSPEC_IS2G( ++ pi->radio_chanspec)) ? (!mode) : 0) << ++ 6 | (!mode) << 5); ++ mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7); ++ } ++} ++ ++void ++wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val, ++ bool iqcalmode) ++{ ++ u8 phy_bw; ++ u16 num_samps, t, k; ++ u32 bw; ++ s32 theta = 0, rot = 0; ++ struct cordic_iq tone_samp; ++ u32 data_buf[64]; ++ u16 i_samp, q_samp; ++ struct phytbl_info tab; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ pi->phy_tx_tone_freq = f_kHz; ++ ++ wlc_lcnphy_deaf_mode(pi, true); ++ ++ phy_bw = 40; ++ if (pi_lcn->lcnphy_spurmod) { ++ write_phy_reg(pi, 0x942, 0x2); ++ write_phy_reg(pi, 0x93b, 0x0); ++ write_phy_reg(pi, 0x93c, 0x0); ++ wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); ++ } ++ ++ if (f_kHz) { ++ k = 1; ++ do { ++ bw = phy_bw * 1000 * k; ++ num_samps = bw / abs(f_kHz); ++ k++; ++ } while ((num_samps * (u32) (abs(f_kHz))) != bw); ++ } else ++ num_samps = 2; ++ ++ rot = ((f_kHz * 36) / phy_bw) / 100; ++ theta = 0; ++ ++ for (t = 0; t < num_samps; t++) { ++ ++ tone_samp = cordic_calc_iq(theta); ++ ++ theta += rot; ++ ++ i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff); ++ q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff); ++ data_buf[t] = (i_samp << 10) | q_samp; ++ } ++ ++ mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3); ++ ++ tab.tbl_ptr = data_buf; ++ tab.tbl_len = num_samps; ++ tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY; ++ tab.tbl_offset = 0; ++ tab.tbl_width = 32; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode); ++} ++ ++void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi) ++{ ++ s16 playback_status; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ pi->phy_tx_tone_freq = 0; ++ if (pi_lcn->lcnphy_spurmod) { ++ write_phy_reg(pi, 0x942, 0x7); ++ write_phy_reg(pi, 0x93b, 0x2017); ++ write_phy_reg(pi, 0x93c, 0x27c5); ++ wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); ++ } ++ ++ playback_status = read_phy_reg(pi, 0x644); ++ if (playback_status & (0x1 << 0)) { ++ wlc_lcnphy_tx_pu(pi, 0); ++ mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1); ++ } else if (playback_status & (0x1 << 1)) ++ mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15); ++ ++ mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3); ++ ++ mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7); ++ ++ and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9); ++ ++ wlc_lcnphy_deaf_mode(pi, false); ++} ++ ++static void ++wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y) ++{ ++ u16 di0dq0; ++ u16 x, y, data_rf; ++ int k; ++ switch (cal_type) { ++ case 0: ++ wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y); ++ break; ++ case 2: ++ di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff); ++ wlc_lcnphy_set_tx_locc(pi, di0dq0); ++ break; ++ case 3: ++ k = wlc_lcnphy_calc_floor(coeff_x, 0); ++ y = 8 + k; ++ k = wlc_lcnphy_calc_floor(coeff_x, 1); ++ x = 8 - k; ++ data_rf = (x * 16 + y); ++ write_radio_reg(pi, RADIO_2064_REG089, data_rf); ++ k = wlc_lcnphy_calc_floor(coeff_y, 0); ++ y = 8 + k; ++ k = wlc_lcnphy_calc_floor(coeff_y, 1); ++ x = 8 - k; ++ data_rf = (x * 16 + y); ++ write_radio_reg(pi, RADIO_2064_REG08A, data_rf); ++ break; ++ case 4: ++ k = wlc_lcnphy_calc_floor(coeff_x, 0); ++ y = 8 + k; ++ k = wlc_lcnphy_calc_floor(coeff_x, 1); ++ x = 8 - k; ++ data_rf = (x * 16 + y); ++ write_radio_reg(pi, RADIO_2064_REG08B, data_rf); ++ k = wlc_lcnphy_calc_floor(coeff_y, 0); ++ y = 8 + k; ++ k = wlc_lcnphy_calc_floor(coeff_y, 1); ++ x = 8 - k; ++ data_rf = (x * 16 + y); ++ write_radio_reg(pi, RADIO_2064_REG08C, data_rf); ++ break; ++ } ++} ++ ++static struct lcnphy_unsign16_struct ++wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type) ++{ ++ u16 a, b, didq; ++ u8 di0, dq0, ei, eq, fi, fq; ++ struct lcnphy_unsign16_struct cc; ++ cc.re = 0; ++ cc.im = 0; ++ switch (cal_type) { ++ case 0: ++ wlc_lcnphy_get_tx_iqcc(pi, &a, &b); ++ cc.re = a; ++ cc.im = b; ++ break; ++ case 2: ++ didq = wlc_lcnphy_get_tx_locc(pi); ++ di0 = (((didq & 0xff00) << 16) >> 24); ++ dq0 = (((didq & 0x00ff) << 24) >> 24); ++ cc.re = (u16) di0; ++ cc.im = (u16) dq0; ++ break; ++ case 3: ++ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); ++ cc.re = (u16) ei; ++ cc.im = (u16) eq; ++ break; ++ case 4: ++ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); ++ cc.re = (u16) fi; ++ cc.im = (u16) fq; ++ break; ++ } ++ return cc; ++} ++ ++static void ++wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, ++ s16 *ptr, int mode) ++{ ++ u32 curval1, curval2, stpptr, curptr, strptr, val; ++ u16 sslpnCalibClkEnCtrl, timer; ++ u16 old_sslpnCalibClkEnCtrl; ++ s16 imag, real; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ timer = 0; ++ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); ++ ++ curval1 = R_REG(&pi->regs->psm_corectlsts); ++ ptr[130] = 0; ++ W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1)); ++ ++ W_REG(&pi->regs->smpl_clct_strptr, 0x7E00); ++ W_REG(&pi->regs->smpl_clct_stpptr, 0x8000); ++ udelay(20); ++ curval2 = R_REG(&pi->regs->psm_phy_hdr_param); ++ W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30); ++ ++ write_phy_reg(pi, 0x555, 0x0); ++ write_phy_reg(pi, 0x5a6, 0x5); ++ ++ write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6)); ++ write_phy_reg(pi, 0x5cf, 3); ++ write_phy_reg(pi, 0x5a5, 0x3); ++ write_phy_reg(pi, 0x583, 0x0); ++ write_phy_reg(pi, 0x584, 0x0); ++ write_phy_reg(pi, 0x585, 0x0fff); ++ write_phy_reg(pi, 0x586, 0x0000); ++ ++ write_phy_reg(pi, 0x580, 0x4501); ++ ++ sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); ++ write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008)); ++ stpptr = R_REG(&pi->regs->smpl_clct_stpptr); ++ curptr = R_REG(&pi->regs->smpl_clct_curptr); ++ do { ++ udelay(10); ++ curptr = R_REG(&pi->regs->smpl_clct_curptr); ++ timer++; ++ } while ((curptr != stpptr) && (timer < 500)); ++ ++ W_REG(&pi->regs->psm_phy_hdr_param, 0x2); ++ strptr = 0x7E00; ++ W_REG(&pi->regs->tplatewrptr, strptr); ++ while (strptr < 0x8000) { ++ val = R_REG(&pi->regs->tplatewrdata); ++ imag = ((val >> 16) & 0x3ff); ++ real = ((val) & 0x3ff); ++ if (imag > 511) ++ imag -= 1024; ++ ++ if (real > 511) ++ real -= 1024; ++ ++ if (pi_lcn->lcnphy_iqcal_swp_dis) ++ ptr[(strptr - 0x7E00) / 4] = real; ++ else ++ ptr[(strptr - 0x7E00) / 4] = imag; ++ ++ if (clip_detect_algo) { ++ if (imag > thresh || imag < -thresh) { ++ strptr = 0x8000; ++ ptr[130] = 1; ++ } ++ } ++ ++ strptr += 4; ++ } ++ ++ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); ++ W_REG(&pi->regs->psm_phy_hdr_param, curval2); ++ W_REG(&pi->regs->psm_corectlsts, curval1); ++} ++ ++static void ++wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, ++ int step_size_lg2) ++{ ++ const struct lcnphy_spb_tone *phy_c1; ++ struct lcnphy_spb_tone phy_c2; ++ struct lcnphy_unsign16_struct phy_c3; ++ int phy_c4, phy_c5, k, l, j, phy_c6; ++ u16 phy_c7, phy_c8, phy_c9; ++ s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16; ++ s16 *ptr, phy_c17; ++ s32 phy_c18, phy_c19; ++ u32 phy_c20, phy_c21; ++ bool phy_c22, phy_c23, phy_c24, phy_c25; ++ u16 phy_c26, phy_c27; ++ u16 phy_c28, phy_c29, phy_c30; ++ u16 phy_c31; ++ u16 *phy_c32; ++ phy_c21 = 0; ++ phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0; ++ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); ++ if (NULL == ptr) ++ return; ++ ++ phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); ++ if (NULL == phy_c32) { ++ kfree(ptr); ++ return; ++ } ++ phy_c26 = read_phy_reg(pi, 0x6da); ++ phy_c27 = read_phy_reg(pi, 0x6db); ++ phy_c31 = read_radio_reg(pi, RADIO_2064_REG026); ++ write_phy_reg(pi, 0x93d, 0xC0); ++ ++ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0); ++ write_phy_reg(pi, 0x6da, 0xffff); ++ or_phy_reg(pi, 0x6db, 0x3); ++ ++ wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32); ++ udelay(500); ++ phy_c28 = read_phy_reg(pi, 0x938); ++ phy_c29 = read_phy_reg(pi, 0x4d7); ++ phy_c30 = read_phy_reg(pi, 0x4d8); ++ or_phy_reg(pi, 0x938, 0x1 << 2); ++ or_phy_reg(pi, 0x4d7, 0x1 << 2); ++ or_phy_reg(pi, 0x4d7, 0x1 << 3); ++ mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12); ++ or_phy_reg(pi, 0x4d8, 1 << 0); ++ or_phy_reg(pi, 0x4d8, 1 << 1); ++ mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2); ++ mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12); ++ phy_c1 = &lcnphy_spb_tone_3750[0]; ++ phy_c4 = 32; ++ ++ if (num_levels == 0) { ++ if (cal_type != 0) ++ num_levels = 4; ++ else ++ num_levels = 9; ++ } ++ if (step_size_lg2 == 0) { ++ if (cal_type != 0) ++ step_size_lg2 = 3; ++ else ++ step_size_lg2 = 8; ++ } ++ ++ phy_c7 = (1 << step_size_lg2); ++ phy_c3 = wlc_lcnphy_get_cc(pi, cal_type); ++ phy_c15 = (s16) phy_c3.re; ++ phy_c16 = (s16) phy_c3.im; ++ if (cal_type == 2) { ++ if (phy_c3.re > 127) ++ phy_c15 = phy_c3.re - 256; ++ if (phy_c3.im > 127) ++ phy_c16 = phy_c3.im - 256; ++ } ++ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); ++ udelay(20); ++ for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) { ++ phy_c23 = 1; ++ phy_c22 = 0; ++ switch (cal_type) { ++ case 0: ++ phy_c10 = 511; ++ break; ++ case 2: ++ phy_c10 = 127; ++ break; ++ case 3: ++ phy_c10 = 15; ++ break; ++ case 4: ++ phy_c10 = 15; ++ break; ++ } ++ ++ phy_c9 = read_phy_reg(pi, 0x93d); ++ phy_c9 = 2 * phy_c9; ++ phy_c24 = 0; ++ phy_c5 = 7; ++ phy_c25 = 1; ++ while (1) { ++ write_radio_reg(pi, RADIO_2064_REG026, ++ (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4)); ++ udelay(50); ++ phy_c22 = 0; ++ ptr[130] = 0; ++ wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2); ++ if (ptr[130] == 1) ++ phy_c22 = 1; ++ if (phy_c22) ++ phy_c5 -= 1; ++ if ((phy_c22 != phy_c24) && (!phy_c25)) ++ break; ++ if (!phy_c22) ++ phy_c5 += 1; ++ if (phy_c5 <= 0 || phy_c5 >= 7) ++ break; ++ phy_c24 = phy_c22; ++ phy_c25 = 0; ++ } ++ ++ if (phy_c5 < 0) ++ phy_c5 = 0; ++ else if (phy_c5 > 7) ++ phy_c5 = 7; ++ ++ for (k = -phy_c7; k <= phy_c7; k += phy_c7) { ++ for (l = -phy_c7; l <= phy_c7; l += phy_c7) { ++ phy_c11 = phy_c15 + k; ++ phy_c12 = phy_c16 + l; ++ ++ if (phy_c11 < -phy_c10) ++ phy_c11 = -phy_c10; ++ else if (phy_c11 > phy_c10) ++ phy_c11 = phy_c10; ++ if (phy_c12 < -phy_c10) ++ phy_c12 = -phy_c10; ++ else if (phy_c12 > phy_c10) ++ phy_c12 = phy_c10; ++ wlc_lcnphy_set_cc(pi, cal_type, phy_c11, ++ phy_c12); ++ udelay(20); ++ wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2); ++ ++ phy_c18 = 0; ++ phy_c19 = 0; ++ for (j = 0; j < 128; j++) { ++ if (cal_type != 0) ++ phy_c6 = j % phy_c4; ++ else ++ phy_c6 = (2 * j) % phy_c4; ++ ++ phy_c2.re = phy_c1[phy_c6].re; ++ phy_c2.im = phy_c1[phy_c6].im; ++ phy_c17 = ptr[j]; ++ phy_c18 = phy_c18 + phy_c17 * phy_c2.re; ++ phy_c19 = phy_c19 + phy_c17 * phy_c2.im; ++ } ++ ++ phy_c18 = phy_c18 >> 10; ++ phy_c19 = phy_c19 >> 10; ++ phy_c20 = ((phy_c18 * phy_c18) + ++ (phy_c19 * phy_c19)); ++ ++ if (phy_c23 || phy_c20 < phy_c21) { ++ phy_c21 = phy_c20; ++ phy_c13 = phy_c11; ++ phy_c14 = phy_c12; ++ } ++ phy_c23 = 0; ++ } ++ } ++ phy_c23 = 1; ++ phy_c15 = phy_c13; ++ phy_c16 = phy_c14; ++ phy_c7 = phy_c7 >> 1; ++ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); ++ udelay(20); ++ } ++ goto cleanup; ++cleanup: ++ wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32); ++ wlc_lcnphy_stop_tx_tone(pi); ++ write_phy_reg(pi, 0x6da, phy_c26); ++ write_phy_reg(pi, 0x6db, phy_c27); ++ write_phy_reg(pi, 0x938, phy_c28); ++ write_phy_reg(pi, 0x4d7, phy_c29); ++ write_phy_reg(pi, 0x4d8, phy_c30); ++ write_radio_reg(pi, RADIO_2064_REG026, phy_c31); ++ ++ kfree(phy_c32); ++ kfree(ptr); ++} ++ ++void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b) ++{ ++ u16 iqcc[2]; ++ struct phytbl_info tab; ++ ++ tab.tbl_ptr = iqcc; ++ tab.tbl_len = 2; ++ tab.tbl_id = 0; ++ tab.tbl_offset = 80; ++ tab.tbl_width = 16; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ *a = iqcc[0]; ++ *b = iqcc[1]; ++} ++ ++static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi) ++{ ++ struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4; ++ ++ wlc_lcnphy_set_cc(pi, 0, 0, 0); ++ wlc_lcnphy_set_cc(pi, 2, 0, 0); ++ wlc_lcnphy_set_cc(pi, 3, 0, 0); ++ wlc_lcnphy_set_cc(pi, 4, 0, 0); ++ ++ wlc_lcnphy_a1(pi, 4, 0, 0); ++ wlc_lcnphy_a1(pi, 3, 0, 0); ++ wlc_lcnphy_a1(pi, 2, 3, 2); ++ wlc_lcnphy_a1(pi, 0, 5, 8); ++ wlc_lcnphy_a1(pi, 2, 2, 1); ++ wlc_lcnphy_a1(pi, 0, 4, 3); ++ ++ iqcc0 = wlc_lcnphy_get_cc(pi, 0); ++ locc2 = wlc_lcnphy_get_cc(pi, 2); ++ locc3 = wlc_lcnphy_get_cc(pi, 3); ++ locc4 = wlc_lcnphy_get_cc(pi, 4); ++} ++ ++u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi) ++{ ++ struct phytbl_info tab; ++ u16 didq; ++ ++ tab.tbl_id = 0; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = &didq; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 85; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ return didq; ++} ++ ++static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) ++{ ++ ++ struct lcnphy_txgains target_gains, old_gains; ++ u8 save_bb_mult; ++ u16 a, b, didq, save_pa_gain = 0; ++ uint idx, SAVE_txpwrindex = 0xFF; ++ u32 val; ++ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ struct phytbl_info tab; ++ u8 ei0, eq0, fi0, fq0; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ wlc_lcnphy_get_tx_gain(pi, &old_gains); ++ save_pa_gain = wlc_lcnphy_get_pa_gain(pi); ++ ++ save_bb_mult = wlc_lcnphy_get_bbmult(pi); ++ ++ if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF) ++ SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ ++ target_gains.gm_gain = 7; ++ target_gains.pga_gain = 0; ++ target_gains.pad_gain = 21; ++ target_gains.dac_gain = 0; ++ wlc_lcnphy_set_tx_gain(pi, &target_gains); ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 16); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { ++ ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 30); ++ ++ wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, ++ (pi_lcn-> ++ lcnphy_recal ? LCNPHY_CAL_RECAL : ++ LCNPHY_CAL_FULL), false); ++ } else { ++ wlc_lcnphy_tx_iqlo_soft_cal_full(pi); ++ } ++ ++ wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0); ++ if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ target_gains.gm_gain = 255; ++ target_gains.pga_gain = 255; ++ target_gains.pad_gain = 0xf0; ++ target_gains.dac_gain = 0; ++ } else { ++ target_gains.gm_gain = 7; ++ target_gains.pga_gain = 45; ++ target_gains.pad_gain = 186; ++ target_gains.dac_gain = 0; ++ } ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1) ++ || pi_lcn->lcnphy_hw_iqcal_en) { ++ ++ target_gains.pga_gain = 0; ++ target_gains.pad_gain = 30; ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 16); ++ wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, ++ LCNPHY_CAL_FULL, false); ++ } else { ++ wlc_lcnphy_tx_iqlo_soft_cal_full(pi); ++ } ++ } ++ ++ wlc_lcnphy_get_tx_iqcc(pi, &a, &b); ++ ++ didq = wlc_lcnphy_get_tx_locc(pi); ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = &val; ++ ++ tab.tbl_len = 1; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; ++ ++ for (idx = 0; idx < 128; idx++) { ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx; ++ ++ wlc_lcnphy_read_table(pi, &tab); ++ val = (val & 0xfff00000) | ++ ((u32) (a & 0x3FF) << 10) | (b & 0x3ff); ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ val = didq; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++ ++ pi_lcn->lcnphy_cal_results.txiqlocal_a = a; ++ pi_lcn->lcnphy_cal_results.txiqlocal_b = b; ++ pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq; ++ pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0; ++ pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0; ++ pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0; ++ pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0; ++ ++ wlc_lcnphy_set_bbmult(pi, save_bb_mult); ++ wlc_lcnphy_set_pa_gain(pi, save_pa_gain); ++ wlc_lcnphy_set_tx_gain(pi, &old_gains); ++ ++ if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF) ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); ++ else ++ wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex); ++} ++ ++s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode) ++{ ++ u16 tempsenseval1, tempsenseval2; ++ s16 avg = 0; ++ bool suspend = 0; ++ ++ if (mode == 1) { ++ suspend = ++ (0 == ++ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); ++ } ++ tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; ++ tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; ++ ++ if (tempsenseval1 > 255) ++ avg = (s16) (tempsenseval1 - 512); ++ else ++ avg = (s16) tempsenseval1; ++ ++ if (tempsenseval2 > 255) ++ avg += (s16) (tempsenseval2 - 512); ++ else ++ avg += (s16) tempsenseval2; ++ ++ avg /= 2; ++ ++ if (mode == 1) { ++ ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); ++ ++ udelay(100); ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ } ++ return avg; ++} ++ ++u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode) ++{ ++ u16 tempsenseval1, tempsenseval2; ++ s32 avg = 0; ++ bool suspend = 0; ++ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ if (mode == 1) { ++ suspend = ++ (0 == ++ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); ++ } ++ tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; ++ tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; ++ ++ if (tempsenseval1 > 255) ++ avg = (int)(tempsenseval1 - 512); ++ else ++ avg = (int)tempsenseval1; ++ ++ if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) { ++ if (tempsenseval2 > 255) ++ avg = (int)(avg - tempsenseval2 + 512); ++ else ++ avg = (int)(avg - tempsenseval2); ++ } else { ++ if (tempsenseval2 > 255) ++ avg = (int)(avg + tempsenseval2 - 512); ++ else ++ avg = (int)(avg + tempsenseval2); ++ avg = avg / 2; ++ } ++ if (avg < 0) ++ avg = avg + 512; ++ ++ if (pi_lcn->lcnphy_tempsense_option == 2) ++ avg = tempsenseval1; ++ ++ if (mode) ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); ++ ++ if (mode == 1) { ++ ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); ++ ++ udelay(100); ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ } ++ return (u16) avg; ++} ++ ++s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode) ++{ ++ s32 degree = wlc_lcnphy_tempsense_new(pi, mode); ++ degree = ++ ((degree << ++ 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1)) ++ / LCN_TEMPSENSE_DEN; ++ return (s8) degree; ++} ++ ++s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode) ++{ ++ u16 vbatsenseval; ++ s32 avg = 0; ++ bool suspend = 0; ++ ++ if (mode == 1) { ++ suspend = ++ (0 == ++ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE); ++ } ++ ++ vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF; ++ ++ if (vbatsenseval > 255) ++ avg = (s32) (vbatsenseval - 512); ++ else ++ avg = (s32) vbatsenseval; ++ ++ avg = (avg * LCN_VBAT_SCALE_NOM + ++ (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN; ++ ++ if (mode == 1) { ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ } ++ return (s8) avg; ++} ++ ++static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode) ++{ ++ u8 phybw40; ++ phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ ++ mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7); ++ ++ if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) || ++ (mode == AFE_CLK_INIT_MODE_TXRX2X)) ++ write_phy_reg(pi, 0x6d0, 0x7); ++ ++ wlc_lcnphy_toggle_afe_pwdn(pi); ++} ++ ++static void wlc_lcnphy_temp_adj(struct brcms_phy *pi) ++{ ++} ++ ++static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi) ++{ ++ bool suspend; ++ s8 index; ++ u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ suspend = ++ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_lcnphy_deaf_mode(pi, true); ++ pi->phy_lastcal = pi->sh->now; ++ pi->phy_forcecal = false; ++ index = pi_lcn->lcnphy_current_index; ++ ++ wlc_lcnphy_txpwrtbl_iqlo_cal(pi); ++ ++ wlc_lcnphy_set_tx_pwr_by_index(pi, index); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); ++ wlc_lcnphy_deaf_mode(pi, false); ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++ ++} ++ ++static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) ++{ ++ bool suspend, full_cal; ++ const struct lcnphy_rx_iqcomp *rx_iqcomp; ++ int rx_iqcomp_sz; ++ u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ s8 index; ++ struct phytbl_info tab; ++ s32 a1, b0, b1; ++ s32 tssi, pwr, maxtargetpwr, mintargetpwr; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ pi->phy_lastcal = pi->sh->now; ++ pi->phy_forcecal = false; ++ full_cal = ++ (pi_lcn->lcnphy_full_cal_channel != ++ CHSPEC_CHANNEL(pi->radio_chanspec)); ++ pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec); ++ index = pi_lcn->lcnphy_current_index; ++ ++ suspend = ++ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) { ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ } ++ ++ wlc_lcnphy_deaf_mode(pi, true); ++ ++ wlc_lcnphy_txpwrtbl_iqlo_cal(pi); ++ ++ rx_iqcomp = lcnphy_rx_iqcomp_table_rev0; ++ rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) ++ wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40); ++ else ++ wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127); ++ ++ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { ++ ++ wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi); ++ ++ b0 = pi->txpa_2g[0]; ++ b1 = pi->txpa_2g[1]; ++ a1 = pi->txpa_2g[2]; ++ maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); ++ mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_ptr = &pwr; ++ tab.tbl_len = 1; ++ tab.tbl_offset = 0; ++ for (tssi = 0; tssi < 128; tssi++) { ++ pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); ++ pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; ++ wlc_lcnphy_write_table(pi, &tab); ++ tab.tbl_offset++; ++ } ++ } ++ ++ wlc_lcnphy_set_tx_pwr_by_index(pi, index); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); ++ wlc_lcnphy_deaf_mode(pi, false); ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode) ++{ ++ u16 temp_new; ++ int temp1, temp2, temp_diff; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ switch (mode) { ++ case PHY_PERICAL_CHAN: ++ break; ++ case PHY_FULLCAL: ++ wlc_lcnphy_periodic_cal(pi); ++ break; ++ case PHY_PERICAL_PHYINIT: ++ wlc_lcnphy_periodic_cal(pi); ++ break; ++ case PHY_PERICAL_WATCHDOG: ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { ++ temp_new = wlc_lcnphy_tempsense(pi, 0); ++ temp1 = LCNPHY_TEMPSENSE(temp_new); ++ temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper); ++ temp_diff = temp1 - temp2; ++ if ((pi_lcn->lcnphy_cal_counter > 90) || ++ (temp_diff > 60) || (temp_diff < -60)) { ++ wlc_lcnphy_glacial_timer_based_cal(pi); ++ wlc_2064_vco_cal(pi); ++ pi_lcn->lcnphy_cal_temper = temp_new; ++ pi_lcn->lcnphy_cal_counter = 0; ++ } else ++ pi_lcn->lcnphy_cal_counter++; ++ } ++ break; ++ case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL: ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ wlc_lcnphy_tx_power_adjustment( ++ (struct brcms_phy_pub *) pi); ++ break; ++ } ++} ++ ++void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr) ++{ ++ s8 cck_offset; ++ u16 status; ++ status = (read_phy_reg(pi, 0x4ab)); ++ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && ++ (status & (0x1 << 15))) { ++ *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) ++ >> 0) >> 1); ++ ++ if (wlc_phy_tpc_isenabled_lcnphy(pi)) ++ cck_offset = pi->tx_power_offset[TXP_FIRST_CCK]; ++ else ++ cck_offset = 0; ++ ++ *cck_pwr = *ofdm_pwr + cck_offset; ++ } else { ++ *cck_pwr = 0; ++ *ofdm_pwr = 0; ++ } ++} ++ ++void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi) ++{ ++ return; ++ ++} ++ ++void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi) ++{ ++ s8 index; ++ u16 index2; ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && ++ SAVE_txpwrctrl) { ++ index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); ++ index2 = (u16) (index * 2); ++ mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); ++ ++ pi_lcn->lcnphy_current_index = ++ (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2); ++ } ++} ++ ++static void ++wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, ++ const struct lcnphy_tx_gain_tbl_entry *gain_table) ++{ ++ u32 j; ++ struct phytbl_info tab; ++ u32 val; ++ u16 pa_gain; ++ u16 gm_gain; ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ pa_gain = 0x70; ++ else ++ pa_gain = 0x70; ++ ++ if (pi->sh->boardflags & BFL_FEM) ++ pa_gain = 0x10; ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_len = 1; ++ tab.tbl_ptr = &val; ++ ++ for (j = 0; j < 128; j++) { ++ gm_gain = gain_table[j].gm; ++ val = (((u32) pa_gain << 24) | ++ (gain_table[j].pad << 16) | ++ (gain_table[j].pga << 8) | gm_gain); ++ ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20); ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++} ++ ++static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi) ++{ ++ struct phytbl_info tab; ++ u32 val, bbmult, rfgain; ++ u8 index; ++ u8 scale_factor = 1; ++ s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift; ++ ++ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; ++ tab.tbl_width = 32; ++ tab.tbl_len = 1; ++ ++ for (index = 0; index < 128; index++) { ++ tab.tbl_ptr = &bbmult; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; ++ wlc_lcnphy_read_table(pi, &tab); ++ bbmult = bbmult >> 20; ++ ++ tab.tbl_ptr = &rfgain; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ qm_log10((s32) (bbmult), 0, &temp1, &qQ1); ++ qm_log10((s32) (1 << 6), 0, &temp2, &qQ2); ++ ++ if (qQ1 < qQ2) { ++ temp2 = qm_shr16(temp2, qQ2 - qQ1); ++ qQ = qQ1; ++ } else { ++ temp1 = qm_shr16(temp1, qQ1 - qQ2); ++ qQ = qQ2; ++ } ++ temp = qm_sub16(temp1, temp2); ++ ++ if (qQ >= 4) ++ shift = qQ - 4; ++ else ++ shift = 4 - qQ; ++ ++ val = (((index << shift) + (5 * temp) + ++ (1 << (scale_factor + shift - 3))) >> (scale_factor + ++ shift - 2)); ++ ++ tab.tbl_ptr = &val; ++ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++} ++ ++static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi) ++{ ++ or_phy_reg(pi, 0x805, 0x1); ++ ++ mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0); ++ ++ mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0); ++ ++ write_phy_reg(pi, 0x414, 0x1e10); ++ write_phy_reg(pi, 0x415, 0x0640); ++ ++ mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8); ++ ++ or_phy_reg(pi, 0x44a, 0x44); ++ write_phy_reg(pi, 0x44a, 0x80); ++ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0); ++ ++ mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0); ++ ++ if (!(pi->sh->boardrev < 0x1204)) ++ mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0); ++ ++ write_phy_reg(pi, 0x7d6, 0x0902); ++ mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0); ++ ++ mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { ++ mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0); ++ ++ mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0); ++ ++ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0); ++ ++ mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0); ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); ++ ++ mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4); ++ mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0); ++ mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90); ++ mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2); ++ mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0); ++ ++ mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2); ++ ++ wlc_lcnphy_clear_tx_power_offsets(pi); ++ mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6); ++ ++ } ++} ++ ++static void wlc_lcnphy_rcal(struct brcms_phy *pi) ++{ ++ u8 rcal_value; ++ ++ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); ++ ++ or_radio_reg(pi, RADIO_2064_REG004, 0x40); ++ or_radio_reg(pi, RADIO_2064_REG120, 0x10); ++ ++ or_radio_reg(pi, RADIO_2064_REG078, 0x80); ++ or_radio_reg(pi, RADIO_2064_REG129, 0x02); ++ ++ or_radio_reg(pi, RADIO_2064_REG057, 0x01); ++ ++ or_radio_reg(pi, RADIO_2064_REG05B, 0x02); ++ mdelay(5); ++ SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000); ++ ++ if (wlc_radio_2064_rcal_done(pi)) { ++ rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C); ++ rcal_value = rcal_value & 0x1f; ++ } ++ ++ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); ++ ++ and_radio_reg(pi, RADIO_2064_REG057, 0xFE); ++} ++ ++static void wlc_lcnphy_rc_cal(struct brcms_phy *pi) ++{ ++ u8 dflt_rc_cal_val; ++ u16 flt_val; ++ ++ dflt_rc_cal_val = 7; ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) ++ dflt_rc_cal_val = 11; ++ flt_val = ++ (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) | ++ (dflt_rc_cal_val); ++ write_phy_reg(pi, 0x933, flt_val); ++ write_phy_reg(pi, 0x934, flt_val); ++ write_phy_reg(pi, 0x935, flt_val); ++ write_phy_reg(pi, 0x936, flt_val); ++ write_phy_reg(pi, 0x937, (flt_val & 0x1FF)); ++ ++ return; ++} ++ ++static void wlc_radio_2064_init(struct brcms_phy *pi) ++{ ++ u32 i; ++ const struct lcnphy_radio_regs *lcnphyregs = NULL; ++ ++ lcnphyregs = lcnphy_radio_regs_2064; ++ ++ for (i = 0; lcnphyregs[i].address != 0xffff; i++) ++ if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a) ++ write_radio_reg(pi, ++ ((lcnphyregs[i].address & 0x3fff) | ++ RADIO_DEFAULT_CORE), ++ (u16) lcnphyregs[i].init_a); ++ else if (lcnphyregs[i].do_init_g) ++ write_radio_reg(pi, ++ ((lcnphyregs[i].address & 0x3fff) | ++ RADIO_DEFAULT_CORE), ++ (u16) lcnphyregs[i].init_g); ++ ++ write_radio_reg(pi, RADIO_2064_REG032, 0x62); ++ write_radio_reg(pi, RADIO_2064_REG033, 0x19); ++ ++ write_radio_reg(pi, RADIO_2064_REG090, 0x10); ++ ++ write_radio_reg(pi, RADIO_2064_REG010, 0x00); ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { ++ ++ write_radio_reg(pi, RADIO_2064_REG060, 0x7f); ++ write_radio_reg(pi, RADIO_2064_REG061, 0x72); ++ write_radio_reg(pi, RADIO_2064_REG062, 0x7f); ++ } ++ ++ write_radio_reg(pi, RADIO_2064_REG01D, 0x02); ++ write_radio_reg(pi, RADIO_2064_REG01E, 0x06); ++ ++ mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0); ++ ++ mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3); ++ ++ mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6); ++ ++ mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9); ++ ++ mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12); ++ ++ write_phy_reg(pi, 0x4ea, 0x4688); ++ ++ mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); ++ ++ mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); ++ ++ mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0); ++ ++ wlc_lcnphy_set_tx_locc(pi, 0); ++ ++ wlc_lcnphy_rcal(pi); ++ ++ wlc_lcnphy_rc_cal(pi); ++} ++ ++static void wlc_lcnphy_radio_init(struct brcms_phy *pi) ++{ ++ wlc_radio_2064_init(pi); ++} ++ ++static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) ++{ ++ uint idx; ++ u8 phybw40; ++ struct phytbl_info tab; ++ u32 val; ++ ++ phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ ++ for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) ++ wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]); ++ ++ if (pi->sh->boardflags & BFL_FEM_BT) { ++ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = &val; ++ tab.tbl_len = 1; ++ val = 100; ++ tab.tbl_offset = 4; ++ wlc_lcnphy_write_table(pi, &tab); ++ } ++ ++ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; ++ tab.tbl_width = 16; ++ tab.tbl_ptr = &val; ++ tab.tbl_len = 1; ++ ++ val = 114; ++ tab.tbl_offset = 0; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ val = 130; ++ tab.tbl_offset = 1; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ val = 6; ++ tab.tbl_offset = 8; ++ wlc_lcnphy_write_table(pi, &tab); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->sh->boardflags & BFL_FEM) ++ wlc_lcnphy_load_tx_gain_table( ++ pi, ++ dot11lcnphy_2GHz_extPA_gaintable_rev0); ++ else ++ wlc_lcnphy_load_tx_gain_table( ++ pi, ++ dot11lcnphy_2GHz_gaintable_rev0); ++ } ++ ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { ++ const struct phytbl_info *tb; ++ int l; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz; ++ if (pi->sh->boardflags & BFL_EXTLNA) ++ tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2; ++ else ++ tb = dot11lcnphytbl_rx_gain_info_2G_rev2; ++ } else { ++ l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz; ++ if (pi->sh->boardflags & BFL_EXTLNA_5GHz) ++ tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2; ++ else ++ tb = dot11lcnphytbl_rx_gain_info_5G_rev2; ++ } ++ ++ for (idx = 0; idx < l; idx++) ++ wlc_lcnphy_write_table(pi, &tb[idx]); ++ } ++ ++ if ((pi->sh->boardflags & BFL_FEM) ++ && !(pi->sh->boardflags & BFL_FEM_BT)) ++ wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa); ++ else if (pi->sh->boardflags & BFL_FEM_BT) { ++ if (pi->sh->boardrev < 0x1250) ++ wlc_lcnphy_write_table( ++ pi, ++ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa); ++ else ++ wlc_lcnphy_write_table( ++ pi, ++ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250); ++ } else ++ wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313); ++ ++ wlc_lcnphy_load_rfpower(pi); ++ ++ wlc_lcnphy_clear_papd_comptable(pi); ++} ++ ++static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi) ++{ ++ u16 afectrl1; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ write_radio_reg(pi, RADIO_2064_REG11C, 0x0); ++ ++ write_phy_reg(pi, 0x43b, 0x0); ++ write_phy_reg(pi, 0x43c, 0x0); ++ write_phy_reg(pi, 0x44c, 0x0); ++ write_phy_reg(pi, 0x4e6, 0x0); ++ write_phy_reg(pi, 0x4f9, 0x0); ++ write_phy_reg(pi, 0x4b0, 0x0); ++ write_phy_reg(pi, 0x938, 0x0); ++ write_phy_reg(pi, 0x4b0, 0x0); ++ write_phy_reg(pi, 0x44e, 0); ++ ++ or_phy_reg(pi, 0x567, 0x03); ++ ++ or_phy_reg(pi, 0x44a, 0x44); ++ write_phy_reg(pi, 0x44a, 0x80); ++ ++ if (!(pi->sh->boardflags & BFL_FEM)) ++ wlc_lcnphy_set_tx_pwr_by_index(pi, 52); ++ ++ if (0) { ++ afectrl1 = 0; ++ afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) | ++ (pi_lcn->lcnphy_rssi_vc << 4) | ++ (pi_lcn->lcnphy_rssi_gs << 10)); ++ write_phy_reg(pi, 0x43e, afectrl1); ++ } ++ ++ mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0); ++ if (pi->sh->boardflags & BFL_FEM) { ++ mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0); ++ ++ write_phy_reg(pi, 0x910, 0x1); ++ } ++ ++ mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8); ++ mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0); ++ mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0); ++ ++} ++ ++static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi) ++{ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0); ++ mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8); ++ } ++} ++ ++static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi) ++{ ++ s16 temp; ++ struct phytbl_info tab; ++ u32 tableBuffer[2]; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ temp = (s16) read_phy_reg(pi, 0x4df); ++ pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0; ++ ++ if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127) ++ pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256; ++ ++ pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8; ++ ++ if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127) ++ pi_lcn->lcnphy_dsssgainidxtableoffset -= 256; ++ ++ tab.tbl_ptr = tableBuffer; ++ tab.tbl_len = 2; ++ tab.tbl_id = 17; ++ tab.tbl_offset = 59; ++ tab.tbl_width = 32; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ if (tableBuffer[0] > 63) ++ tableBuffer[0] -= 128; ++ pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0]; ++ ++ if (tableBuffer[1] > 63) ++ tableBuffer[1] -= 128; ++ pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1]; ++ ++ temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0)); ++ if (temp > 127) ++ temp -= 256; ++ pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp; ++ ++ pi_lcn->lcnphy_Med_Low_Gain_db = ++ (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8; ++ pi_lcn->lcnphy_Very_Low_Gain_db = ++ (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0; ++ ++ tab.tbl_ptr = tableBuffer; ++ tab.tbl_len = 2; ++ tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX; ++ tab.tbl_offset = 28; ++ tab.tbl_width = 32; ++ wlc_lcnphy_read_table(pi, &tab); ++ ++ pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0]; ++ pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1]; ++ ++} ++ ++static void wlc_lcnphy_baseband_init(struct brcms_phy *pi) ++{ ++ ++ wlc_lcnphy_tbl_init(pi); ++ wlc_lcnphy_rev0_baseband_init(pi); ++ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) ++ wlc_lcnphy_rev2_baseband_init(pi); ++ wlc_lcnphy_bu_tweaks(pi); ++} ++ ++void wlc_phy_init_lcnphy(struct brcms_phy *pi) ++{ ++ u8 phybw40; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ ++ pi_lcn->lcnphy_cal_counter = 0; ++ pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense; ++ ++ or_phy_reg(pi, 0x44a, 0x80); ++ and_phy_reg(pi, 0x44a, 0x7f); ++ ++ wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X); ++ ++ write_phy_reg(pi, 0x60a, 160); ++ ++ write_phy_reg(pi, 0x46a, 25); ++ ++ wlc_lcnphy_baseband_init(pi); ++ ++ wlc_lcnphy_radio_init(pi); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi); ++ ++ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec); ++ ++ si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9); ++ ++ si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD); ++ ++ if ((pi->sh->boardflags & BFL_FEM) ++ && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR); ++ ++ wlc_lcnphy_agc_temp_init(pi); ++ ++ wlc_lcnphy_temp_adj(pi); ++ ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); ++ ++ udelay(100); ++ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); ++ ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); ++ pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT; ++ wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT); ++} ++ ++static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) ++{ ++ s8 txpwr = 0; ++ int i; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ struct phy_shim_info *shim = pi->sh->physhim; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ u16 cckpo = 0; ++ u32 offset_ofdm, offset_mcs; ++ ++ pi_lcn->lcnphy_tr_isolation_mid = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); ++ ++ pi_lcn->lcnphy_rx_power_offset = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G); ++ ++ pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0); ++ pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1); ++ pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2); ++ ++ pi_lcn->lcnphy_rssi_vf = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G); ++ pi_lcn->lcnphy_rssi_vc = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G); ++ pi_lcn->lcnphy_rssi_gs = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G); ++ ++ pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf; ++ pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc; ++ pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs; ++ ++ pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf; ++ pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc; ++ pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs; ++ ++ txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0); ++ pi->tx_srom_max_2g = txpwr; ++ ++ for (i = 0; i < PWRTBL_NUM_COEFF; i++) { ++ pi->txpa_2g_low_temp[i] = pi->txpa_2g[i]; ++ pi->txpa_2g_high_temp[i] = pi->txpa_2g[i]; ++ } ++ ++ cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO); ++ offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO); ++ if (cckpo) { ++ uint max_pwr_chan = txpwr; ++ ++ for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) { ++ pi->tx_srom_max_rate_2g[i] = ++ max_pwr_chan - ((cckpo & 0xf) * 2); ++ cckpo >>= 4; ++ } ++ ++ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { ++ pi->tx_srom_max_rate_2g[i] = ++ max_pwr_chan - ++ ((offset_ofdm & 0xf) * 2); ++ offset_ofdm >>= 4; ++ } ++ } else { ++ u8 opo = 0; ++ ++ opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO); ++ ++ for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) ++ pi->tx_srom_max_rate_2g[i] = txpwr; ++ ++ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { ++ pi->tx_srom_max_rate_2g[i] = txpwr - ++ ((offset_ofdm & 0xf) * 2); ++ offset_ofdm >>= 4; ++ } ++ offset_mcs = ++ wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO1) << 16; ++ offset_mcs |= ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO0); ++ pi_lcn->lcnphy_mcs20_po = offset_mcs; ++ for (i = TXP_FIRST_SISO_MCS_20; ++ i <= TXP_LAST_SISO_MCS_20; i++) { ++ pi->tx_srom_max_rate_2g[i] = ++ txpwr - ((offset_mcs & 0xf) * 2); ++ offset_mcs >>= 4; ++ } ++ } ++ ++ pi_lcn->lcnphy_rawtempsense = ++ (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE); ++ pi_lcn->lcnphy_measPower = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER); ++ pi_lcn->lcnphy_tempsense_slope = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE); ++ pi_lcn->lcnphy_hw_iqcal_en = ++ (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN); ++ pi_lcn->lcnphy_iqcal_swp_dis = ++ (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS); ++ pi_lcn->lcnphy_tempcorrx = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX); ++ pi_lcn->lcnphy_tempsense_option = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION); ++ pi_lcn->lcnphy_freqoffset_corr = ++ (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR); ++ if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1) ++ wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, ++ (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G)); ++ } ++ pi_lcn->lcnphy_cck_dig_filt_type = -1; ++ ++ return true; ++} ++ ++void wlc_2064_vco_cal(struct brcms_phy *pi) ++{ ++ u8 calnrst; ++ ++ mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3); ++ calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8; ++ write_radio_reg(pi, RADIO_2064_REG056, calnrst); ++ udelay(1); ++ write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03); ++ udelay(1); ++ write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07); ++ udelay(300); ++ mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0); ++} ++ ++bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi) ++{ ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) ++ return 0; ++ else ++ return (LCNPHY_TX_PWR_CTRL_HW == ++ wlc_lcnphy_get_tx_pwr_ctrl((pi))); ++} ++ ++void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi) ++{ ++ u16 pwr_ctrl; ++ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { ++ wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); ++ } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { ++ pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); ++ wlc_lcnphy_txpower_recalc_target(pi); ++ wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl); ++ } ++} ++ ++void wlc_phy_detach_lcnphy(struct brcms_phy *pi) ++{ ++ kfree(pi->u.pi_lcnphy); ++} ++ ++bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) ++{ ++ struct brcms_phy_lcnphy *pi_lcn; ++ ++ pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC); ++ if (pi->u.pi_lcnphy == NULL) ++ return false; ++ ++ pi_lcn = pi->u.pi_lcnphy; ++ ++ if (0 == (pi->sh->boardflags & BFL_NOPA)) { ++ pi->hwpwrctrl = true; ++ pi->hwpwrctrl_capable = true; ++ } ++ ++ pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih); ++ pi_lcn->lcnphy_papd_rxGnCtrl_init = 0; ++ ++ pi->pi_fptr.init = wlc_phy_init_lcnphy; ++ pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy; ++ pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy; ++ pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy; ++ pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc; ++ pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc; ++ pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc; ++ pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft; ++ pi->pi_fptr.detach = wlc_phy_detach_lcnphy; ++ ++ if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) ++ return false; ++ ++ if ((pi->sh->boardflags & BFL_FEM) && ++ (LCNREV_IS(pi->pubpi.phy_rev, 1))) { ++ if (pi_lcn->lcnphy_tempsense_option == 3) { ++ pi->hwpwrctrl = true; ++ pi->hwpwrctrl_capable = true; ++ pi->temppwrctrl_capable = false; ++ } else { ++ pi->hwpwrctrl = false; ++ pi->hwpwrctrl_capable = false; ++ pi->temppwrctrl_capable = true; ++ } ++ } ++ ++ return true; ++} ++ ++static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain) ++{ ++ u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19; ++ ++ trsw = (gain & ((u32) 1 << 28)) ? 0 : 1; ++ ext_lna = (u16) (gain >> 29) & 0x01; ++ lna1 = (u16) (gain >> 0) & 0x0f; ++ lna2 = (u16) (gain >> 4) & 0x0f; ++ tia = (u16) (gain >> 8) & 0xf; ++ biq0 = (u16) (gain >> 12) & 0xf; ++ biq1 = (u16) (gain >> 16) & 0xf; ++ ++ gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) | ++ ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) | ++ ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12)); ++ gain16_19 = biq1; ++ ++ mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0); ++ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); ++ mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); ++ mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); ++ mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); ++ mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); ++ } ++ wlc_lcnphy_rx_gain_override_enable(pi, true); ++} ++ ++static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index) ++{ ++ u32 received_power = 0; ++ s32 max_index = 0; ++ u32 gain_code = 0; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ max_index = 36; ++ if (*gain_index >= 0) ++ gain_code = lcnphy_23bitgaincode_table[*gain_index]; ++ ++ if (-1 == *gain_index) { ++ *gain_index = 0; ++ while ((*gain_index <= (s32) max_index) ++ && (received_power < 700)) { ++ wlc_lcnphy_set_rx_gain(pi, ++ lcnphy_23bitgaincode_table ++ [*gain_index]); ++ received_power = ++ wlc_lcnphy_measure_digital_power( ++ pi, ++ pi_lcn-> ++ lcnphy_noise_samples); ++ (*gain_index)++; ++ } ++ (*gain_index)--; ++ } else { ++ wlc_lcnphy_set_rx_gain(pi, gain_code); ++ received_power = ++ wlc_lcnphy_measure_digital_power(pi, ++ pi_lcn-> ++ lcnphy_noise_samples); ++ } ++ ++ return received_power; ++} ++ ++s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index) ++{ ++ s32 gain = 0; ++ s32 nominal_power_db; ++ s32 log_val, gain_mismatch, desired_gain, input_power_offset_db, ++ input_power_db; ++ s32 received_power, temperature; ++ u32 power; ++ u32 msb1, msb2, val1, val2, diff1, diff2; ++ uint freq; ++ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; ++ ++ received_power = wlc_lcnphy_get_receive_power(pi, &gain_index); ++ ++ gain = lcnphy_gain_table[gain_index]; ++ ++ nominal_power_db = read_phy_reg(pi, 0x425) >> 8; ++ ++ power = (received_power * 16); ++ msb1 = ffs(power) - 1; ++ msb2 = msb1 + 1; ++ val1 = 1 << msb1; ++ val2 = 1 << msb2; ++ diff1 = (power - val1); ++ diff2 = (val2 - power); ++ if (diff1 < diff2) ++ log_val = msb1; ++ else ++ log_val = msb2; ++ ++ log_val = log_val * 3; ++ ++ gain_mismatch = (nominal_power_db / 2) - (log_val); ++ ++ desired_gain = gain + gain_mismatch; ++ ++ input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF; ++ ++ if (input_power_offset_db > 127) ++ input_power_offset_db -= 256; ++ ++ input_power_db = input_power_offset_db - desired_gain; ++ ++ input_power_db = ++ input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index]; ++ ++ freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec)); ++ if ((freq > 2427) && (freq <= 2467)) ++ input_power_db = input_power_db - 1; ++ ++ temperature = pi_lcn->lcnphy_lastsensed_temperature; ++ ++ if ((temperature - 15) < -30) ++ input_power_db = ++ input_power_db + ++ (((temperature - 10 - 25) * 286) >> 12) - ++ 7; ++ else if ((temperature - 15) < 4) ++ input_power_db = ++ input_power_db + ++ (((temperature - 10 - 25) * 286) >> 12) - ++ 3; ++ else ++ input_power_db = input_power_db + ++ (((temperature - 10 - 25) * 286) >> 12); ++ ++ wlc_lcnphy_rx_gain_override_enable(pi, 0); ++ ++ return input_power_db; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h.orig 2011-11-09 13:46:58.258800470 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h 2011-11-09 13:47:17.012566015 -0500 +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_PHY_LCN_H_ ++#define _BRCM_PHY_LCN_H_ ++ ++#include ++ ++struct brcms_phy_lcnphy { ++ int lcnphy_txrf_sp_9_override; ++ u8 lcnphy_full_cal_channel; ++ u8 lcnphy_cal_counter; ++ u16 lcnphy_cal_temper; ++ bool lcnphy_recal; ++ ++ u8 lcnphy_rc_cap; ++ u32 lcnphy_mcs20_po; ++ ++ u8 lcnphy_tr_isolation_mid; ++ u8 lcnphy_tr_isolation_low; ++ u8 lcnphy_tr_isolation_hi; ++ ++ u8 lcnphy_bx_arch; ++ u8 lcnphy_rx_power_offset; ++ u8 lcnphy_rssi_vf; ++ u8 lcnphy_rssi_vc; ++ u8 lcnphy_rssi_gs; ++ u8 lcnphy_tssi_val; ++ u8 lcnphy_rssi_vf_lowtemp; ++ u8 lcnphy_rssi_vc_lowtemp; ++ u8 lcnphy_rssi_gs_lowtemp; ++ ++ u8 lcnphy_rssi_vf_hightemp; ++ u8 lcnphy_rssi_vc_hightemp; ++ u8 lcnphy_rssi_gs_hightemp; ++ ++ s16 lcnphy_pa0b0; ++ s16 lcnphy_pa0b1; ++ s16 lcnphy_pa0b2; ++ ++ u16 lcnphy_rawtempsense; ++ u8 lcnphy_measPower; ++ u8 lcnphy_tempsense_slope; ++ u8 lcnphy_freqoffset_corr; ++ u8 lcnphy_tempsense_option; ++ u8 lcnphy_tempcorrx; ++ bool lcnphy_iqcal_swp_dis; ++ bool lcnphy_hw_iqcal_en; ++ uint lcnphy_bandedge_corr; ++ bool lcnphy_spurmod; ++ u16 lcnphy_tssi_tx_cnt; ++ u16 lcnphy_tssi_idx; ++ u16 lcnphy_tssi_npt; ++ ++ u16 lcnphy_target_tx_freq; ++ s8 lcnphy_tx_power_idx_override; ++ u16 lcnphy_noise_samples; ++ ++ u32 lcnphy_papdRxGnIdx; ++ u32 lcnphy_papd_rxGnCtrl_init; ++ ++ u32 lcnphy_gain_idx_14_lowword; ++ u32 lcnphy_gain_idx_14_hiword; ++ u32 lcnphy_gain_idx_27_lowword; ++ u32 lcnphy_gain_idx_27_hiword; ++ s16 lcnphy_ofdmgainidxtableoffset; ++ s16 lcnphy_dsssgainidxtableoffset; ++ u32 lcnphy_tr_R_gain_val; ++ u32 lcnphy_tr_T_gain_val; ++ s8 lcnphy_input_pwr_offset_db; ++ u16 lcnphy_Med_Low_Gain_db; ++ u16 lcnphy_Very_Low_Gain_db; ++ s8 lcnphy_lastsensed_temperature; ++ s8 lcnphy_pkteng_rssi_slope; ++ u8 lcnphy_saved_tx_user_target[TXP_NUM_RATES]; ++ u8 lcnphy_volt_winner; ++ u8 lcnphy_volt_low; ++ u8 lcnphy_54_48_36_24mbps_backoff; ++ u8 lcnphy_11n_backoff; ++ u8 lcnphy_lowerofdm; ++ u8 lcnphy_cck; ++ u8 lcnphy_psat_2pt3_detected; ++ s32 lcnphy_lowest_Re_div_Im; ++ s8 lcnphy_final_papd_cal_idx; ++ u16 lcnphy_extstxctrl4; ++ u16 lcnphy_extstxctrl0; ++ u16 lcnphy_extstxctrl1; ++ s16 lcnphy_cck_dig_filt_type; ++ s16 lcnphy_ofdm_dig_filt_type; ++ struct lcnphy_cal_results lcnphy_cal_results; ++ ++ u8 lcnphy_psat_pwr; ++ u8 lcnphy_psat_indx; ++ s32 lcnphy_min_phase; ++ u8 lcnphy_final_idx; ++ u8 lcnphy_start_idx; ++ u8 lcnphy_current_index; ++ u16 lcnphy_logen_buf_1; ++ u16 lcnphy_local_ovr_2; ++ u16 lcnphy_local_oval_6; ++ u16 lcnphy_local_oval_5; ++ u16 lcnphy_logen_mixer_1; ++ ++ u8 lcnphy_aci_stat; ++ uint lcnphy_aci_start_time; ++ s8 lcnphy_tx_power_offset[TXP_NUM_RATES]; ++}; ++#endif /* _BRCM_PHY_LCN_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c.orig 2011-11-09 13:46:58.275800257 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c 2011-11-09 13:47:17.032565765 -0500 +@@ -0,0 +1,28876 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "phy_int.h" ++#include "phy_hal.h" ++#include "phy_radio.h" ++#include "phyreg_n.h" ++#include "phytbl_n.h" ++ ++#define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name) \ ++ read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \ ++ ((core == PHY_CORE_0) ? \ ++ radio_type##_##jspace##0 : \ ++ radio_type##_##jspace##1)) ++ ++#define WRITE_RADIO_REG2(pi, radio_type, jspace, core, reg_name, value) \ ++ write_radio_reg(pi, radio_type##_##jspace##_##reg_name | \ ++ ((core == PHY_CORE_0) ? \ ++ radio_type##_##jspace##0 : \ ++ radio_type##_##jspace##1), value) ++ ++#define WRITE_RADIO_SYN(pi, radio_type, reg_name, value) \ ++ write_radio_reg(pi, radio_type##_##SYN##_##reg_name, value) ++ ++#define READ_RADIO_REG3(pi, radio_type, jspace, core, reg_name) \ ++ read_radio_reg(pi, ((core == PHY_CORE_0) ? \ ++ radio_type##_##jspace##0##_##reg_name : \ ++ radio_type##_##jspace##1##_##reg_name)) ++ ++#define WRITE_RADIO_REG3(pi, radio_type, jspace, core, reg_name, value) \ ++ write_radio_reg(pi, ((core == PHY_CORE_0) ? \ ++ radio_type##_##jspace##0##_##reg_name : \ ++ radio_type##_##jspace##1##_##reg_name), \ ++ value) ++ ++#define READ_RADIO_REG4(pi, radio_type, jspace, core, reg_name) \ ++ read_radio_reg(pi, ((core == PHY_CORE_0) ? \ ++ radio_type##_##reg_name##_##jspace##0 : \ ++ radio_type##_##reg_name##_##jspace##1)) ++ ++#define WRITE_RADIO_REG4(pi, radio_type, jspace, core, reg_name, value) \ ++ write_radio_reg(pi, ((core == PHY_CORE_0) ? \ ++ radio_type##_##reg_name##_##jspace##0 : \ ++ radio_type##_##reg_name##_##jspace##1), \ ++ value) ++ ++#define NPHY_ACI_MAX_UNDETECT_WINDOW_SZ 40 ++#define NPHY_ACI_CHANNEL_DELTA 5 ++#define NPHY_ACI_CHANNEL_SKIP 4 ++#define NPHY_ACI_40MHZ_CHANNEL_DELTA 6 ++#define NPHY_ACI_40MHZ_CHANNEL_SKIP 5 ++#define NPHY_ACI_40MHZ_CHANNEL_DELTA_GE_REV3 6 ++#define NPHY_ACI_40MHZ_CHANNEL_SKIP_GE_REV3 5 ++#define NPHY_ACI_CHANNEL_DELTA_GE_REV3 4 ++#define NPHY_ACI_CHANNEL_SKIP_GE_REV3 3 ++ ++#define NPHY_NOISE_NOASSOC_GLITCH_TH_UP 2 ++ ++#define NPHY_NOISE_NOASSOC_GLITCH_TH_DN 8 ++ ++#define NPHY_NOISE_ASSOC_GLITCH_TH_UP 2 ++ ++#define NPHY_NOISE_ASSOC_GLITCH_TH_DN 8 ++ ++#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_UP 2 ++ ++#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_DN 8 ++ ++#define NPHY_NOISE_NOASSOC_ENTER_TH 400 ++ ++#define NPHY_NOISE_ASSOC_ENTER_TH 400 ++ ++#define NPHY_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH 400 ++ ++#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX 44 ++#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX_REV_7 56 ++ ++#define NPHY_NOISE_NOASSOC_CRSIDX_INCR 16 ++ ++#define NPHY_NOISE_ASSOC_CRSIDX_INCR 8 ++ ++#define NPHY_IS_SROM_REINTERPRET NREV_GE(pi->pubpi.phy_rev, 5) ++ ++#define NPHY_RSSICAL_MAXREAD 31 ++ ++#define NPHY_RSSICAL_NPOLL 8 ++#define NPHY_RSSICAL_MAXD (1<<20) ++#define NPHY_MIN_RXIQ_PWR 2 ++ ++#define NPHY_RSSICAL_W1_TARGET 25 ++#define NPHY_RSSICAL_W2_TARGET NPHY_RSSICAL_W1_TARGET ++#define NPHY_RSSICAL_NB_TARGET 0 ++ ++#define NPHY_RSSICAL_W1_TARGET_REV3 29 ++#define NPHY_RSSICAL_W2_TARGET_REV3 NPHY_RSSICAL_W1_TARGET_REV3 ++ ++#define NPHY_CALSANITY_RSSI_NB_MAX_POS 9 ++#define NPHY_CALSANITY_RSSI_NB_MAX_NEG -9 ++#define NPHY_CALSANITY_RSSI_W1_MAX_POS 12 ++#define NPHY_CALSANITY_RSSI_W1_MAX_NEG (NPHY_RSSICAL_W1_TARGET - \ ++ NPHY_RSSICAL_MAXREAD) ++#define NPHY_CALSANITY_RSSI_W2_MAX_POS NPHY_CALSANITY_RSSI_W1_MAX_POS ++#define NPHY_CALSANITY_RSSI_W2_MAX_NEG (NPHY_RSSICAL_W2_TARGET - \ ++ NPHY_RSSICAL_MAXREAD) ++#define NPHY_RSSI_SXT(x) ((s8) (-((x) & 0x20) + ((x) & 0x1f))) ++#define NPHY_RSSI_NB_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_NB_MAX_POS) || \ ++ ((x) < NPHY_CALSANITY_RSSI_NB_MAX_NEG)) ++#define NPHY_RSSI_W1_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W1_MAX_POS) || \ ++ ((x) < NPHY_CALSANITY_RSSI_W1_MAX_NEG)) ++#define NPHY_RSSI_W2_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W2_MAX_POS) || \ ++ ((x) < NPHY_CALSANITY_RSSI_W2_MAX_NEG)) ++ ++#define NPHY_IQCAL_NUMGAINS 9 ++#define NPHY_N_GCTL 0x66 ++ ++#define NPHY_PAPD_EPS_TBL_SIZE 64 ++#define NPHY_PAPD_SCL_TBL_SIZE 64 ++#define NPHY_NUM_DIG_FILT_COEFFS 15 ++ ++#define NPHY_PAPD_COMP_OFF 0 ++#define NPHY_PAPD_COMP_ON 1 ++ ++#define NPHY_SROM_TEMPSHIFT 32 ++#define NPHY_SROM_MAXTEMPOFFSET 16 ++#define NPHY_SROM_MINTEMPOFFSET -16 ++ ++#define NPHY_CAL_MAXTEMPDELTA 64 ++ ++#define NPHY_NOISEVAR_TBLLEN40 256 ++#define NPHY_NOISEVAR_TBLLEN20 128 ++ ++#define NPHY_ANARXLPFBW_REDUCTIONFACT 7 ++ ++#define NPHY_ADJUSTED_MINCRSPOWER 0x1e ++ ++/* 5357 Chip specific ChipControl register bits */ ++#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */ ++#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */ ++ ++#define NPHY_CAL_TSSISAMPS 64 ++#define NPHY_TEST_TONE_FREQ_40MHz 4000 ++#define NPHY_TEST_TONE_FREQ_20MHz 2500 ++ ++#define MAX_205x_RCAL_WAITLOOPS 10000 ++ ++#define NPHY_RXCAL_TONEAMP 181 ++#define NPHY_RXCAL_TONEFREQ_40MHz 4000 ++#define NPHY_RXCAL_TONEFREQ_20MHz 2000 ++ ++#define TXFILT_SHAPING_OFDM20 0 ++#define TXFILT_SHAPING_OFDM40 1 ++#define TXFILT_SHAPING_CCK 2 ++#define TXFILT_DEFAULT_OFDM20 3 ++#define TXFILT_DEFAULT_OFDM40 4 ++ ++struct nphy_iqcal_params { ++ u16 txlpf; ++ u16 txgm; ++ u16 pga; ++ u16 pad; ++ u16 ipa; ++ u16 cal_gain; ++ u16 ncorr[5]; ++}; ++ ++struct nphy_txiqcal_ladder { ++ u8 percent; ++ u8 g_env; ++}; ++ ++struct nphy_ipa_txcalgains { ++ struct nphy_txgains gains; ++ bool useindex; ++ u8 index; ++}; ++ ++struct nphy_papd_restore_state { ++ u16 fbmix[2]; ++ u16 vga_master[2]; ++ u16 intpa_master[2]; ++ u16 afectrl[2]; ++ u16 afeoverride[2]; ++ u16 pwrup[2]; ++ u16 atten[2]; ++ u16 mm; ++}; ++ ++struct nphy_ipa_txrxgain { ++ u16 hpvga; ++ u16 lpf_biq1; ++ u16 lpf_biq0; ++ u16 lna2; ++ u16 lna1; ++ s8 txpwrindex; ++}; ++ ++#define NPHY_IPA_RXCAL_MAXGAININDEX (6 - 1) ++ ++static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = { ++ {0, 0, 0, 0, 0, 100}, ++ {0, 0, 0, 0, 0, 50}, ++ {0, 0, 0, 0, 0, -1}, ++ {0, 0, 0, 3, 0, -1}, ++ {0, 0, 3, 3, 0, -1}, ++ {0, 2, 3, 3, 0, -1} ++}; ++ ++static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = { ++ {0, 0, 0, 0, 0, 128}, ++ {0, 0, 0, 0, 0, 70}, ++ {0, 0, 0, 0, 0, 20}, ++ {0, 0, 0, 3, 0, 20}, ++ {0, 0, 3, 3, 0, 20}, ++ {0, 2, 3, 3, 0, 20} ++}; ++ ++static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz_rev7[] = { ++ {0, 0, 0, 0, 0, 100}, ++ {0, 0, 0, 0, 0, 50}, ++ {0, 0, 0, 0, 0, -1}, ++ {0, 0, 0, 3, 0, -1}, ++ {0, 0, 3, 3, 0, -1}, ++ {0, 0, 5, 3, 0, -1} ++}; ++ ++static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz_rev7[] = { ++ {0, 0, 0, 0, 0, 10}, ++ {0, 0, 0, 1, 0, 10}, ++ {0, 0, 1, 2, 0, 10}, ++ {0, 0, 1, 3, 0, 10}, ++ {0, 0, 4, 3, 0, 10}, ++ {0, 0, 6, 3, 0, 10} ++}; ++ ++enum { ++ NPHY_RXCAL_GAIN_INIT = 0, ++ NPHY_RXCAL_GAIN_UP, ++ NPHY_RXCAL_GAIN_DOWN ++}; ++ ++#define wlc_phy_get_papd_nphy(pi) \ ++ (read_phy_reg((pi), 0x1e7) & \ ++ ((0x1 << 15) | \ ++ (0x1 << 14) | \ ++ (0x1 << 13))) ++ ++static const u16 NPHY_IPA_REV4_txdigi_filtcoeffs[][NPHY_NUM_DIG_FILT_COEFFS] = { ++ {-377, 137, -407, 208, -1527, 956, 93, 186, 93, ++ 230, -44, 230, 201, -191, 201}, ++ {-77, 20, -98, 49, -93, 60, 56, 111, 56, 26, -5, ++ 26, 34, -32, 34}, ++ {-360, 164, -376, 164, -1533, 576, 308, -314, 308, ++ 121, -73, 121, 91, 124, 91}, ++ {-295, 200, -363, 142, -1391, 826, 151, 301, 151, ++ 151, 301, 151, 602, -752, 602}, ++ {-92, 58, -96, 49, -104, 44, 17, 35, 17, ++ 12, 25, 12, 13, 27, 13}, ++ {-375, 136, -399, 209, -1479, 949, 130, 260, 130, ++ 230, -44, 230, 201, -191, 201}, ++ {0xed9, 0xc8, 0xe95, 0x8e, 0xa91, 0x33a, 0x97, 0x12d, 0x97, ++ 0x97, 0x12d, 0x97, 0x25a, 0xd10, 0x25a} ++}; ++ ++struct chan_info_nphy_2055 { ++ u16 chan; ++ u16 freq; ++ uint unknown; ++ u8 RF_pll_ref; ++ u8 RF_rf_pll_mod1; ++ u8 RF_rf_pll_mod0; ++ u8 RF_vco_cap_tail; ++ u8 RF_vco_cal1; ++ u8 RF_vco_cal2; ++ u8 RF_pll_lf_c1; ++ u8 RF_pll_lf_r1; ++ u8 RF_pll_lf_c2; ++ u8 RF_lgbuf_cen_buf; ++ u8 RF_lgen_tune1; ++ u8 RF_lgen_tune2; ++ u8 RF_core1_lgbuf_a_tune; ++ u8 RF_core1_lgbuf_g_tune; ++ u8 RF_core1_rxrf_reg1; ++ u8 RF_core1_tx_pga_pad_tn; ++ u8 RF_core1_tx_mx_bgtrim; ++ u8 RF_core2_lgbuf_a_tune; ++ u8 RF_core2_lgbuf_g_tune; ++ u8 RF_core2_rxrf_reg1; ++ u8 RF_core2_tx_pga_pad_tn; ++ u8 RF_core2_tx_mx_bgtrim; ++ u16 PHY_BW1a; ++ u16 PHY_BW2; ++ u16 PHY_BW3; ++ u16 PHY_BW4; ++ u16 PHY_BW5; ++ u16 PHY_BW6; ++}; ++ ++struct chan_info_nphy_radio205x { ++ u16 chan; ++ u16 freq; ++ u8 RF_SYN_pll_vcocal1; ++ u8 RF_SYN_pll_vcocal2; ++ u8 RF_SYN_pll_refdiv; ++ u8 RF_SYN_pll_mmd2; ++ u8 RF_SYN_pll_mmd1; ++ u8 RF_SYN_pll_loopfilter1; ++ u8 RF_SYN_pll_loopfilter2; ++ u8 RF_SYN_pll_loopfilter3; ++ u8 RF_SYN_pll_loopfilter4; ++ u8 RF_SYN_pll_loopfilter5; ++ u8 RF_SYN_reserved_addr27; ++ u8 RF_SYN_reserved_addr28; ++ u8 RF_SYN_reserved_addr29; ++ u8 RF_SYN_logen_VCOBUF1; ++ u8 RF_SYN_logen_MIXER2; ++ u8 RF_SYN_logen_BUF3; ++ u8 RF_SYN_logen_BUF4; ++ u8 RF_RX0_lnaa_tune; ++ u8 RF_RX0_lnag_tune; ++ u8 RF_TX0_intpaa_boost_tune; ++ u8 RF_TX0_intpag_boost_tune; ++ u8 RF_TX0_pada_boost_tune; ++ u8 RF_TX0_padg_boost_tune; ++ u8 RF_TX0_pgaa_boost_tune; ++ u8 RF_TX0_pgag_boost_tune; ++ u8 RF_TX0_mixa_boost_tune; ++ u8 RF_TX0_mixg_boost_tune; ++ u8 RF_RX1_lnaa_tune; ++ u8 RF_RX1_lnag_tune; ++ u8 RF_TX1_intpaa_boost_tune; ++ u8 RF_TX1_intpag_boost_tune; ++ u8 RF_TX1_pada_boost_tune; ++ u8 RF_TX1_padg_boost_tune; ++ u8 RF_TX1_pgaa_boost_tune; ++ u8 RF_TX1_pgag_boost_tune; ++ u8 RF_TX1_mixa_boost_tune; ++ u8 RF_TX1_mixg_boost_tune; ++ u16 PHY_BW1a; ++ u16 PHY_BW2; ++ u16 PHY_BW3; ++ u16 PHY_BW4; ++ u16 PHY_BW5; ++ u16 PHY_BW6; ++}; ++ ++struct chan_info_nphy_radio2057 { ++ u16 chan; ++ u16 freq; ++ u8 RF_vcocal_countval0; ++ u8 RF_vcocal_countval1; ++ u8 RF_rfpll_refmaster_sparextalsize; ++ u8 RF_rfpll_loopfilter_r1; ++ u8 RF_rfpll_loopfilter_c2; ++ u8 RF_rfpll_loopfilter_c1; ++ u8 RF_cp_kpd_idac; ++ u8 RF_rfpll_mmd0; ++ u8 RF_rfpll_mmd1; ++ u8 RF_vcobuf_tune; ++ u8 RF_logen_mx2g_tune; ++ u8 RF_logen_mx5g_tune; ++ u8 RF_logen_indbuf2g_tune; ++ u8 RF_logen_indbuf5g_tune; ++ u8 RF_txmix2g_tune_boost_pu_core0; ++ u8 RF_pad2g_tune_pus_core0; ++ u8 RF_pga_boost_tune_core0; ++ u8 RF_txmix5g_boost_tune_core0; ++ u8 RF_pad5g_tune_misc_pus_core0; ++ u8 RF_lna2g_tune_core0; ++ u8 RF_lna5g_tune_core0; ++ u8 RF_txmix2g_tune_boost_pu_core1; ++ u8 RF_pad2g_tune_pus_core1; ++ u8 RF_pga_boost_tune_core1; ++ u8 RF_txmix5g_boost_tune_core1; ++ u8 RF_pad5g_tune_misc_pus_core1; ++ u8 RF_lna2g_tune_core1; ++ u8 RF_lna5g_tune_core1; ++ u16 PHY_BW1a; ++ u16 PHY_BW2; ++ u16 PHY_BW3; ++ u16 PHY_BW4; ++ u16 PHY_BW5; ++ u16 PHY_BW6; ++}; ++ ++struct chan_info_nphy_radio2057_rev5 { ++ u16 chan; ++ u16 freq; ++ u8 RF_vcocal_countval0; ++ u8 RF_vcocal_countval1; ++ u8 RF_rfpll_refmaster_sparextalsize; ++ u8 RF_rfpll_loopfilter_r1; ++ u8 RF_rfpll_loopfilter_c2; ++ u8 RF_rfpll_loopfilter_c1; ++ u8 RF_cp_kpd_idac; ++ u8 RF_rfpll_mmd0; ++ u8 RF_rfpll_mmd1; ++ u8 RF_vcobuf_tune; ++ u8 RF_logen_mx2g_tune; ++ u8 RF_logen_indbuf2g_tune; ++ u8 RF_txmix2g_tune_boost_pu_core0; ++ u8 RF_pad2g_tune_pus_core0; ++ u8 RF_lna2g_tune_core0; ++ u8 RF_txmix2g_tune_boost_pu_core1; ++ u8 RF_pad2g_tune_pus_core1; ++ u8 RF_lna2g_tune_core1; ++ u16 PHY_BW1a; ++ u16 PHY_BW2; ++ u16 PHY_BW3; ++ u16 PHY_BW4; ++ u16 PHY_BW5; ++ u16 PHY_BW6; ++}; ++ ++struct nphy_sfo_cfg { ++ u16 PHY_BW1a; ++ u16 PHY_BW2; ++ u16 PHY_BW3; ++ u16 PHY_BW4; ++ u16 PHY_BW5; ++ u16 PHY_BW6; ++}; ++ ++static const struct chan_info_nphy_2055 chan_info_nphy_2055[] = { ++ { ++ 184, 4920, 3280, 0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7B4, 0x7B0, 0x7AC, 0x214, 0x215, 0x216}, ++ { ++ 186, 4930, 3287, 0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7B8, 0x7B4, 0x7B0, 0x213, 0x214, 0x215}, ++ { ++ 188, 4940, 3293, 0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7BC, 0x7B8, 0x7B4, 0x212, 0x213, 0x214}, ++ { ++ 190, 4950, 3300, 0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7C0, 0x7BC, 0x7B8, 0x211, 0x212, 0x213}, ++ { ++ 192, 4960, 3307, 0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7C4, 0x7C0, 0x7BC, 0x20F, 0x211, 0x212}, ++ { ++ 194, 4970, 3313, 0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7C8, 0x7C4, 0x7C0, 0x20E, 0x20F, 0x211}, ++ { ++ 196, 4980, 3320, 0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7CC, 0x7C8, 0x7C4, 0x20D, 0x20E, 0x20F}, ++ { ++ 198, 4990, 3327, 0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7D0, 0x7CC, 0x7C8, 0x20C, 0x20D, 0x20E}, ++ { ++ 200, 5000, 3333, 0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7D4, 0x7D0, 0x7CC, 0x20B, 0x20C, 0x20D}, ++ { ++ 202, 5010, 3340, 0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7D8, 0x7D4, 0x7D0, 0x20A, 0x20B, 0x20C}, ++ { ++ 204, 5020, 3347, 0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7DC, 0x7D8, 0x7D4, 0x209, 0x20A, 0x20B}, ++ { ++ 206, 5030, 3353, 0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7E0, 0x7DC, 0x7D8, 0x208, 0x209, 0x20A}, ++ { ++ 208, 5040, 3360, 0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7E4, 0x7E0, 0x7DC, 0x207, 0x208, 0x209}, ++ { ++ 210, 5050, 3367, 0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, ++ 0x0F, 0x8F, 0x7E8, 0x7E4, 0x7E0, 0x206, 0x207, 0x208}, ++ { ++ 212, 5060, 3373, 0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E, ++ 0x0F, 0x8E, 0x7EC, 0x7E8, 0x7E4, 0x205, 0x206, 0x207}, ++ { ++ 214, 5070, 3380, 0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E, ++ 0x0F, 0x8E, 0x7F0, 0x7EC, 0x7E8, 0x204, 0x205, 0x206}, ++ { ++ 216, 5080, 3387, 0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E, ++ 0x0F, 0x8D, 0x7F4, 0x7F0, 0x7EC, 0x203, 0x204, 0x205}, ++ { ++ 218, 5090, 3393, 0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E, ++ 0x0F, 0x8D, 0x7F8, 0x7F4, 0x7F0, 0x202, 0x203, 0x204}, ++ { ++ 220, 5100, 3400, 0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D, ++ 0x0F, 0x8D, 0x7FC, 0x7F8, 0x7F4, 0x201, 0x202, 0x203}, ++ { ++ 222, 5110, 3407, 0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D, ++ 0x0F, 0x8D, 0x800, 0x7FC, 0x7F8, 0x200, 0x201, 0x202}, ++ { ++ 224, 5120, 3413, 0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D, ++ 0x0F, 0x8C, 0x804, 0x800, 0x7FC, 0x1FF, 0x200, 0x201}, ++ { ++ 226, 5130, 3420, 0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D, ++ 0x0F, 0x8C, 0x808, 0x804, 0x800, 0x1FE, 0x1FF, 0x200}, ++ { ++ 228, 5140, 3427, 0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, 0x8B, 0xDD, 0x00, 0x0C, ++ 0x0E, 0x8B, 0x80C, 0x808, 0x804, 0x1FD, 0x1FE, 0x1FF}, ++ { ++ 32, 5160, 3440, 0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B, ++ 0x0D, 0x8A, 0x814, 0x810, 0x80C, 0x1FB, 0x1FC, 0x1FD}, ++ { ++ 34, 5170, 3447, 0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, ++ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B, ++ 0x0D, 0x8A, 0x818, 0x814, 0x810, 0x1FA, 0x1FB, 0x1FC}, ++ { ++ 36, 5180, 3453, 0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B, ++ 0x0C, 0x89, 0x81C, 0x818, 0x814, 0x1F9, 0x1FA, 0x1FB}, ++ { ++ 38, 5190, 3460, 0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, ++ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B, ++ 0x0C, 0x89, 0x820, 0x81C, 0x818, 0x1F8, 0x1F9, 0x1FA}, ++ { ++ 40, 5200, 3467, 0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A, ++ 0x0B, 0x89, 0x824, 0x820, 0x81C, 0x1F7, 0x1F8, 0x1F9}, ++ { ++ 42, 5210, 3473, 0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, ++ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A, ++ 0x0B, 0x89, 0x828, 0x824, 0x820, 0x1F6, 0x1F7, 0x1F8}, ++ { ++ 44, 5220, 3480, 0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, ++ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09, ++ 0x0A, 0x88, 0x82C, 0x828, 0x824, 0x1F5, 0x1F6, 0x1F7}, ++ { ++ 46, 5230, 3487, 0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, ++ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09, ++ 0x0A, 0x88, 0x830, 0x82C, 0x828, 0x1F4, 0x1F5, 0x1F6}, ++ { ++ 48, 5240, 3493, 0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, ++ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09, ++ 0x0A, 0x87, 0x834, 0x830, 0x82C, 0x1F3, 0x1F4, 0x1F5}, ++ { ++ 50, 5250, 3500, 0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, ++ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09, ++ 0x0A, 0x87, 0x838, 0x834, 0x830, 0x1F2, 0x1F3, 0x1F4}, ++ { ++ 52, 5260, 3507, 0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, ++ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08, ++ 0x09, 0x87, 0x83C, 0x838, 0x834, 0x1F1, 0x1F2, 0x1F3}, ++ { ++ 54, 5270, 3513, 0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, ++ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08, ++ 0x09, 0x87, 0x840, 0x83C, 0x838, 0x1F0, 0x1F1, 0x1F2}, ++ { ++ 56, 5280, 3520, 0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, ++ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08, ++ 0x08, 0x86, 0x844, 0x840, 0x83C, 0x1F0, 0x1F0, 0x1F1}, ++ { ++ 58, 5290, 3527, 0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, ++ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08, ++ 0x08, 0x86, 0x848, 0x844, 0x840, 0x1EF, 0x1F0, 0x1F0}, ++ { ++ 60, 5300, 3533, 0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, ++ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08, ++ 0x07, 0x85, 0x84C, 0x848, 0x844, 0x1EE, 0x1EF, 0x1F0}, ++ { ++ 62, 5310, 3540, 0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, ++ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08, ++ 0x07, 0x85, 0x850, 0x84C, 0x848, 0x1ED, 0x1EE, 0x1EF}, ++ { ++ 64, 5320, 3547, 0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, ++ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07, ++ 0x07, 0x84, 0x854, 0x850, 0x84C, 0x1EC, 0x1ED, 0x1EE}, ++ { ++ 66, 5330, 3553, 0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, ++ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07, ++ 0x07, 0x84, 0x858, 0x854, 0x850, 0x1EB, 0x1EC, 0x1ED}, ++ { ++ 68, 5340, 3560, 0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, ++ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07, ++ 0x06, 0x84, 0x85C, 0x858, 0x854, 0x1EA, 0x1EB, 0x1EC}, ++ { ++ 70, 5350, 3567, 0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, ++ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07, ++ 0x06, 0x84, 0x860, 0x85C, 0x858, 0x1E9, 0x1EA, 0x1EB}, ++ { ++ 72, 5360, 3573, 0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, ++ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06, ++ 0x05, 0x83, 0x864, 0x860, 0x85C, 0x1E8, 0x1E9, 0x1EA}, ++ { ++ 74, 5370, 3580, 0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, ++ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06, ++ 0x05, 0x83, 0x868, 0x864, 0x860, 0x1E7, 0x1E8, 0x1E9}, ++ { ++ 76, 5380, 3587, 0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, ++ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06, ++ 0x04, 0x82, 0x86C, 0x868, 0x864, 0x1E6, 0x1E7, 0x1E8}, ++ { ++ 78, 5390, 3593, 0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, ++ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06, ++ 0x04, 0x82, 0x870, 0x86C, 0x868, 0x1E5, 0x1E6, 0x1E7}, ++ { ++ 80, 5400, 3600, 0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, ++ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05, ++ 0x04, 0x81, 0x874, 0x870, 0x86C, 0x1E5, 0x1E5, 0x1E6}, ++ { ++ 82, 5410, 3607, 0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, ++ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05, ++ 0x04, 0x81, 0x878, 0x874, 0x870, 0x1E4, 0x1E5, 0x1E5}, ++ { ++ 84, 5420, 3613, 0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, ++ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05, ++ 0x03, 0x80, 0x87C, 0x878, 0x874, 0x1E3, 0x1E4, 0x1E5}, ++ { ++ 86, 5430, 3620, 0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, ++ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05, ++ 0x03, 0x80, 0x880, 0x87C, 0x878, 0x1E2, 0x1E3, 0x1E4}, ++ { ++ 88, 5440, 3627, 0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, ++ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04, ++ 0x02, 0x80, 0x884, 0x880, 0x87C, 0x1E1, 0x1E2, 0x1E3}, ++ { ++ 90, 5450, 3633, 0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, ++ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04, ++ 0x02, 0x80, 0x888, 0x884, 0x880, 0x1E0, 0x1E1, 0x1E2}, ++ { ++ 92, 5460, 3640, 0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, ++ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04, ++ 0x01, 0x80, 0x88C, 0x888, 0x884, 0x1DF, 0x1E0, 0x1E1}, ++ { ++ 94, 5470, 3647, 0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, ++ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04, ++ 0x01, 0x80, 0x890, 0x88C, 0x888, 0x1DE, 0x1DF, 0x1E0}, ++ { ++ 96, 5480, 3653, 0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, ++ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, ++ 0x00, 0x80, 0x894, 0x890, 0x88C, 0x1DD, 0x1DE, 0x1DF}, ++ { ++ 98, 5490, 3660, 0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, ++ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, ++ 0x00, 0x80, 0x898, 0x894, 0x890, 0x1DD, 0x1DD, 0x1DE}, ++ { ++ 100, 5500, 3667, 0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, ++ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, ++ 0x00, 0x80, 0x89C, 0x898, 0x894, 0x1DC, 0x1DD, 0x1DD}, ++ { ++ 102, 5510, 3673, 0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, ++ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, ++ 0x00, 0x80, 0x8A0, 0x89C, 0x898, 0x1DB, 0x1DC, 0x1DD}, ++ { ++ 104, 5520, 3680, 0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, ++ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, ++ 0x00, 0x80, 0x8A4, 0x8A0, 0x89C, 0x1DA, 0x1DB, 0x1DC}, ++ { ++ 106, 5530, 3687, 0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, ++ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, ++ 0x00, 0x80, 0x8A8, 0x8A4, 0x8A0, 0x1D9, 0x1DA, 0x1DB}, ++ { ++ 108, 5540, 3693, 0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, ++ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, ++ 0x00, 0x80, 0x8AC, 0x8A8, 0x8A4, 0x1D8, 0x1D9, 0x1DA}, ++ { ++ 110, 5550, 3700, 0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, ++ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, ++ 0x00, 0x80, 0x8B0, 0x8AC, 0x8A8, 0x1D7, 0x1D8, 0x1D9}, ++ { ++ 112, 5560, 3707, 0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, ++ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, ++ 0x00, 0x80, 0x8B4, 0x8B0, 0x8AC, 0x1D7, 0x1D7, 0x1D8}, ++ { ++ 114, 5570, 3713, 0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, ++ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, ++ 0x00, 0x80, 0x8B8, 0x8B4, 0x8B0, 0x1D6, 0x1D7, 0x1D7}, ++ { ++ 116, 5580, 3720, 0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, ++ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, ++ 0x00, 0x80, 0x8BC, 0x8B8, 0x8B4, 0x1D5, 0x1D6, 0x1D7}, ++ { ++ 118, 5590, 3727, 0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, ++ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, ++ 0x00, 0x80, 0x8C0, 0x8BC, 0x8B8, 0x1D4, 0x1D5, 0x1D6}, ++ { ++ 120, 5600, 3733, 0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, ++ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01, ++ 0x00, 0x80, 0x8C4, 0x8C0, 0x8BC, 0x1D3, 0x1D4, 0x1D5}, ++ { ++ 122, 5610, 3740, 0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, ++ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01, ++ 0x00, 0x80, 0x8C8, 0x8C4, 0x8C0, 0x1D2, 0x1D3, 0x1D4}, ++ { ++ 124, 5620, 3747, 0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, ++ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, ++ 0x00, 0x80, 0x8CC, 0x8C8, 0x8C4, 0x1D2, 0x1D2, 0x1D3}, ++ { ++ 126, 5630, 3753, 0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, ++ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, ++ 0x00, 0x80, 0x8D0, 0x8CC, 0x8C8, 0x1D1, 0x1D2, 0x1D2}, ++ { ++ 128, 5640, 3760, 0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8D4, 0x8D0, 0x8CC, 0x1D0, 0x1D1, 0x1D2}, ++ { ++ 130, 5650, 3767, 0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8D8, 0x8D4, 0x8D0, 0x1CF, 0x1D0, 0x1D1}, ++ { ++ 132, 5660, 3773, 0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8DC, 0x8D8, 0x8D4, 0x1CE, 0x1CF, 0x1D0}, ++ { ++ 134, 5670, 3780, 0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8E0, 0x8DC, 0x8D8, 0x1CE, 0x1CE, 0x1CF}, ++ { ++ 136, 5680, 3787, 0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8E4, 0x8E0, 0x8DC, 0x1CD, 0x1CE, 0x1CE}, ++ { ++ 138, 5690, 3793, 0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8E8, 0x8E4, 0x8E0, 0x1CC, 0x1CD, 0x1CE}, ++ { ++ 140, 5700, 3800, 0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8EC, 0x8E8, 0x8E4, 0x1CB, 0x1CC, 0x1CD}, ++ { ++ 142, 5710, 3807, 0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8F0, 0x8EC, 0x8E8, 0x1CA, 0x1CB, 0x1CC}, ++ { ++ 144, 5720, 3813, 0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8F4, 0x8F0, 0x8EC, 0x1C9, 0x1CA, 0x1CB}, ++ { ++ 145, 5725, 3817, 0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8F6, 0x8F2, 0x8EE, 0x1C9, 0x1CA, 0x1CB}, ++ { ++ 146, 5730, 3820, 0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8F8, 0x8F4, 0x8F0, 0x1C9, 0x1C9, 0x1CA}, ++ { ++ 147, 5735, 3823, 0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8FA, 0x8F6, 0x8F2, 0x1C8, 0x1C9, 0x1CA}, ++ { ++ 148, 5740, 3827, 0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8FC, 0x8F8, 0x8F4, 0x1C8, 0x1C9, 0x1C9}, ++ { ++ 149, 5745, 3830, 0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x8FE, 0x8FA, 0x8F6, 0x1C8, 0x1C8, 0x1C9}, ++ { ++ 150, 5750, 3833, 0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x900, 0x8FC, 0x8F8, 0x1C7, 0x1C8, 0x1C9}, ++ { ++ 151, 5755, 3837, 0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x902, 0x8FE, 0x8FA, 0x1C7, 0x1C8, 0x1C8}, ++ { ++ 152, 5760, 3840, 0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x904, 0x900, 0x8FC, 0x1C6, 0x1C7, 0x1C8}, ++ { ++ 153, 5765, 3843, 0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x906, 0x902, 0x8FE, 0x1C6, 0x1C7, 0x1C8}, ++ { ++ 154, 5770, 3847, 0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x908, 0x904, 0x900, 0x1C6, 0x1C6, 0x1C7}, ++ { ++ 155, 5775, 3850, 0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x90A, 0x906, 0x902, 0x1C5, 0x1C6, 0x1C7}, ++ { ++ 156, 5780, 3853, 0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x90C, 0x908, 0x904, 0x1C5, 0x1C6, 0x1C6}, ++ { ++ 157, 5785, 3857, 0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x90E, 0x90A, 0x906, 0x1C4, 0x1C5, 0x1C6}, ++ { ++ 158, 5790, 3860, 0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x910, 0x90C, 0x908, 0x1C4, 0x1C5, 0x1C6}, ++ { ++ 159, 5795, 3863, 0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x912, 0x90E, 0x90A, 0x1C4, 0x1C4, 0x1C5}, ++ { ++ 160, 5800, 3867, 0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x914, 0x910, 0x90C, 0x1C3, 0x1C4, 0x1C5}, ++ { ++ 161, 5805, 3870, 0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x916, 0x912, 0x90E, 0x1C3, 0x1C4, 0x1C4}, ++ { ++ 162, 5810, 3873, 0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x918, 0x914, 0x910, 0x1C2, 0x1C3, 0x1C4}, ++ { ++ 163, 5815, 3877, 0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x91A, 0x916, 0x912, 0x1C2, 0x1C3, 0x1C4}, ++ { ++ 164, 5820, 3880, 0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x91C, 0x918, 0x914, 0x1C2, 0x1C2, 0x1C3}, ++ { ++ 165, 5825, 3883, 0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x91E, 0x91A, 0x916, 0x1C1, 0x1C2, 0x1C3}, ++ { ++ 166, 5830, 3887, 0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x920, 0x91C, 0x918, 0x1C1, 0x1C2, 0x1C2}, ++ { ++ 168, 5840, 3893, 0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x924, 0x920, 0x91C, 0x1C0, 0x1C1, 0x1C2}, ++ { ++ 170, 5850, 3900, 0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x928, 0x924, 0x920, 0x1BF, 0x1C0, 0x1C1}, ++ { ++ 172, 5860, 3907, 0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x92C, 0x928, 0x924, 0x1BF, 0x1BF, 0x1C0}, ++ { ++ 174, 5870, 3913, 0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x930, 0x92C, 0x928, 0x1BE, 0x1BF, 0x1BF}, ++ { ++ 176, 5880, 3920, 0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x934, 0x930, 0x92C, 0x1BD, 0x1BE, 0x1BF}, ++ { ++ 178, 5890, 3927, 0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x938, 0x934, 0x930, 0x1BC, 0x1BD, 0x1BE}, ++ { ++ 180, 5900, 3933, 0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x93C, 0x938, 0x934, 0x1BC, 0x1BC, 0x1BD}, ++ { ++ 182, 5910, 3940, 0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x80, 0x940, 0x93C, 0x938, 0x1BB, 0x1BC, 0x1BC}, ++ { ++ 1, 2412, 3216, 0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, 0x80, 0xFF, 0x88, 0x0D, ++ 0x0C, 0x80, 0x3C9, 0x3C5, 0x3C1, 0x43A, 0x43F, 0x443}, ++ { ++ 2, 2417, 3223, 0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, 0x80, 0xFF, 0x88, 0x0C, ++ 0x0B, 0x80, 0x3CB, 0x3C7, 0x3C3, 0x438, 0x43D, 0x441}, ++ { ++ 3, 2422, 3229, 0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C, ++ 0x0A, 0x80, 0x3CD, 0x3C9, 0x3C5, 0x436, 0x43A, 0x43F}, ++ { ++ 4, 2427, 3236, 0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C, ++ 0x0A, 0x80, 0x3CF, 0x3CB, 0x3C7, 0x434, 0x438, 0x43D}, ++ { ++ 5, 2432, 3243, 0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, 0x80, 0xFF, 0x88, 0x0C, ++ 0x09, 0x80, 0x3D1, 0x3CD, 0x3C9, 0x431, 0x436, 0x43A}, ++ { ++ 6, 2437, 3249, 0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, 0x80, 0xFF, 0x88, 0x0B, ++ 0x08, 0x80, 0x3D3, 0x3CF, 0x3CB, 0x42F, 0x434, 0x438}, ++ { ++ 7, 2442, 3256, 0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, 0x80, 0xFF, 0x88, 0x0A, ++ 0x07, 0x80, 0x3D5, 0x3D1, 0x3CD, 0x42D, 0x431, 0x436}, ++ { ++ 8, 2447, 3263, 0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, 0x80, 0xFF, 0x88, 0x0A, ++ 0x06, 0x80, 0x3D7, 0x3D3, 0x3CF, 0x42B, 0x42F, 0x434}, ++ { ++ 9, 2452, 3269, 0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, 0x80, 0xFF, 0x88, 0x09, ++ 0x06, 0x80, 0x3D9, 0x3D5, 0x3D1, 0x429, 0x42D, 0x431}, ++ { ++ 10, 2457, 3276, 0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, 0x80, 0xFF, 0x88, 0x08, ++ 0x05, 0x80, 0x3DB, 0x3D7, 0x3D3, 0x427, 0x42B, 0x42F}, ++ { ++ 11, 2462, 3283, 0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, 0x80, 0xFF, 0x88, 0x08, ++ 0x04, 0x80, 0x3DD, 0x3D9, 0x3D5, 0x424, 0x429, 0x42D}, ++ { ++ 12, 2467, 3289, 0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, 0x80, 0xFF, 0x88, 0x08, ++ 0x03, 0x80, 0x3DF, 0x3DB, 0x3D7, 0x422, 0x427, 0x42B}, ++ { ++ 13, 2472, 3296, 0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, 0x80, 0xFF, 0x88, 0x07, ++ 0x03, 0x80, 0x3E1, 0x3DD, 0x3D9, 0x420, 0x424, 0x429}, ++ { ++ 14, 2484, 3312, 0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, ++ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, 0x80, 0xFF, 0x88, 0x07, ++ 0x01, 0x80, 0x3E6, 0x3E2, 0x3DE, 0x41B, 0x41F, 0x424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xff, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xfc, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfc, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x05, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xfa, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, ++ 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf8, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf6, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf6, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf6, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf6, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf6, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf4, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf2, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf2, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf2, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, ++ 0x00, 0xf2, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x05, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, ++ 0x00, 0xf2, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x05, 0x00, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, ++ 0x00, 0xf2, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf7, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf6, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0f, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf5, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0d, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0d, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf3, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0d, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0d, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x05, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0d, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfe, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x08, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x07, 0x00, 0x7f, ++ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, ++ 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x5c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, ++ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, ++ 0x00, 0xf6, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x04, 0x00, 0x7f, ++ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, ++ 0x00, 0xf4, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, ++ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, ++ 0x00, 0xf2, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, ++ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, ++ 0x00, 0xf0, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf0, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, ++ 0x00, 0x07, 0x00, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, ++ 0x00, 0xf0, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfd, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf7, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf5, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf3, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x04, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0e, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, ++ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xea, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xd9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xd8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa7, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x5b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x96, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x5a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x5a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x5a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x5a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x5a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x85, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x59, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x59, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x59, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x74, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x63, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x75, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x75, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x75, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x74, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x84, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x83, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x72, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x72, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x72, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x72, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x71, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x71, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x71, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x71, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x71, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x08, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x07, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x05, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, ++ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, ++ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, ++ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xfa, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, ++ 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xea, 0x00, 0x06, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xe9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xe9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xd9, 0x00, 0x05, 0x00, 0x70, ++ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, ++ 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xd8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb8, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xb7, 0x00, 0x04, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xb7, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, ++ 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa7, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x7b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x96, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x7a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x7a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, ++ 0x00, 0x7a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x7a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x95, 0x00, 0x03, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x7a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x85, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x79, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x79, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, ++ 0x00, 0x79, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x79, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x74, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x79, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, ++ 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x63, 0x00, 0x01, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, ++ 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x52, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x52, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x86, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x51, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, ++ 0x00, 0x85, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x85, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x85, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x84, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x84, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, ++ 0x00, 0x94, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x93, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x92, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x76, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x66, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x55, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x22, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = { ++ { ++ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, ++ { ++ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, ++ { ++ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, ++ { ++ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, ++ { ++ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, ++ { ++ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, ++ { ++ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, ++ { ++ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, ++ { ++ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, ++ { ++ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, ++ { ++ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, ++ { ++ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, ++ { ++ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, ++ { ++ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, ++ { ++ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, ++ { ++ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, ++ { ++ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, ++ { ++ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, ++ { ++ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, ++ { ++ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, ++ { ++ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, ++ { ++ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, ++ { ++ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, ++ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, ++ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, ++ { ++ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, ++ { ++ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, ++ { ++ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, ++ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, ++ { ++ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, ++ { ++ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, ++ { ++ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, ++ { ++ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, ++ { ++ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, ++ { ++ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, ++ { ++ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, ++ { ++ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, ++ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, ++ { ++ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, ++ { ++ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, ++ { ++ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, ++ { ++ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, ++ { ++ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, ++ { ++ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, ++ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, ++ { ++ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, ++ { ++ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, ++ { ++ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, ++ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, ++ { ++ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, ++ { ++ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, ++ { ++ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, ++ { ++ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, ++ { ++ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, ++ { ++ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, ++ { ++ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, ++ { ++ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, ++ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, ++ { ++ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, ++ { ++ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, ++ { ++ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, ++ { ++ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, ++ { ++ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, ++ { ++ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, ++ { ++ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, ++ { ++ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, ++ { ++ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, ++ { ++ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, ++ { ++ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, ++ { ++ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, ++ { ++ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, ++ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, ++ { ++ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, ++ { ++ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, ++ { ++ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, ++ { ++ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, ++ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, ++ { ++ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, ++ { ++ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, ++ { ++ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, ++ { ++ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, ++ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, ++ { ++ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, ++ { ++ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, ++ { ++ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, ++ { ++ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, ++ { ++ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, ++ { ++ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, ++ { ++ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, ++ { ++ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, ++ { ++ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, ++ { ++ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, ++ { ++ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, ++ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, ++ { ++ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, ++ { ++ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, ++ { ++ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, ++ { ++ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, ++ { ++ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, ++ { ++ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, ++ { ++ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, ++ { ++ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, ++ { ++ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, ++ { ++ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, ++ { ++ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, ++ { ++ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, ++ { ++ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x05, 0x05, 0x02, 0x15, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, ++ { ++ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, ++ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, ++ { ++ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, ++ { ++ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, ++ { ++ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, ++ { ++ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, ++ { ++ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, ++ { ++ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, ++ { ++ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, ++ { ++ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x02, 0x0c, 0x01, ++ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, ++ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, ++ { ++ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x06, 0x06, 0x04, 0x2b, 0x01, ++ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, ++ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = { ++ { ++ 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b4, 0x07b0, 0x07ac, 0x0214, ++ 0x0215, ++ 0x0216, ++ }, ++ { ++ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b8, 0x07b4, 0x07b0, 0x0213, ++ 0x0214, ++ 0x0215, ++ }, ++ { ++ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07bc, 0x07b8, 0x07b4, 0x0212, ++ 0x0213, ++ 0x0214, ++ }, ++ { ++ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c0, 0x07bc, 0x07b8, 0x0211, ++ 0x0212, ++ 0x0213, ++ }, ++ { ++ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c4, 0x07c0, 0x07bc, 0x020f, ++ 0x0211, ++ 0x0212, ++ }, ++ { ++ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c8, 0x07c4, 0x07c0, 0x020e, ++ 0x020f, ++ 0x0211, ++ }, ++ { ++ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07cc, 0x07c8, 0x07c4, 0x020d, ++ 0x020e, ++ 0x020f, ++ }, ++ { ++ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d0, 0x07cc, 0x07c8, 0x020c, ++ 0x020d, ++ 0x020e, ++ }, ++ { ++ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d4, 0x07d0, 0x07cc, 0x020b, ++ 0x020c, ++ 0x020d, ++ }, ++ { ++ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d8, 0x07d4, 0x07d0, 0x020a, ++ 0x020b, ++ 0x020c, ++ }, ++ { ++ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07dc, 0x07d8, 0x07d4, 0x0209, ++ 0x020a, ++ 0x020b, ++ }, ++ { ++ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e0, 0x07dc, 0x07d8, 0x0208, ++ 0x0209, ++ 0x020a, ++ }, ++ { ++ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e4, 0x07e0, 0x07dc, 0x0207, ++ 0x0208, ++ 0x0209, ++ }, ++ { ++ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e8, 0x07e4, 0x07e0, 0x0206, ++ 0x0207, ++ 0x0208, ++ }, ++ { ++ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x00, ++ 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x07ec, 0x07e8, 0x07e4, 0x0205, ++ 0x0206, ++ 0x0207, ++ }, ++ { ++ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f0, 0x07ec, 0x07e8, 0x0204, ++ 0x0205, ++ 0x0206, ++ }, ++ { ++ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f4, 0x07f0, 0x07ec, 0x0203, ++ 0x0204, ++ 0x0205, ++ }, ++ { ++ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07f8, 0x07f4, 0x07f0, 0x0202, ++ 0x0203, ++ 0x0204, ++ }, ++ { ++ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07fc, 0x07f8, 0x07f4, 0x0201, ++ 0x0202, ++ 0x0203, ++ }, ++ { ++ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0800, 0x07fc, 0x07f8, 0x0200, ++ 0x0201, ++ 0x0202, ++ }, ++ { ++ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0804, 0x0800, 0x07fc, 0x01ff, ++ 0x0200, ++ 0x0201, ++ }, ++ { ++ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0808, 0x0804, 0x0800, 0x01fe, ++ 0x01ff, ++ 0x0200, ++ }, ++ { ++ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x080c, 0x0808, 0x0804, 0x01fd, ++ 0x01fe, ++ 0x01ff, ++ }, ++ { ++ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0814, 0x0810, 0x080c, 0x01fb, ++ 0x01fc, ++ 0x01fd, ++ }, ++ { ++ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0818, 0x0814, 0x0810, 0x01fa, ++ 0x01fb, ++ 0x01fc, ++ }, ++ { ++ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x081c, 0x0818, 0x0814, 0x01f9, ++ 0x01fa, ++ 0x01fb, ++ }, ++ { ++ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0820, 0x081c, 0x0818, 0x01f8, ++ 0x01f9, ++ 0x01fa, ++ }, ++ { ++ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0824, 0x0820, 0x081c, 0x01f7, ++ 0x01f8, ++ 0x01f9, ++ }, ++ { ++ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0828, 0x0824, 0x0820, 0x01f6, ++ 0x01f7, ++ 0x01f8, ++ }, ++ { ++ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x082c, 0x0828, 0x0824, 0x01f5, ++ 0x01f6, ++ 0x01f7, ++ }, ++ { ++ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0830, 0x082c, 0x0828, 0x01f4, ++ 0x01f5, ++ 0x01f6, ++ }, ++ { ++ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0834, 0x0830, 0x082c, 0x01f3, ++ 0x01f4, ++ 0x01f5, ++ }, ++ { ++ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0838, 0x0834, 0x0830, 0x01f2, ++ 0x01f3, ++ 0x01f4, ++ }, ++ { ++ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x083c, 0x0838, 0x0834, 0x01f1, ++ 0x01f2, ++ 0x01f3, ++ }, ++ { ++ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00, ++ 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x0840, 0x083c, 0x0838, 0x01f0, ++ 0x01f1, ++ 0x01f2, ++ }, ++ { ++ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0844, 0x0840, 0x083c, 0x01f0, ++ 0x01f0, ++ 0x01f1, ++ }, ++ { ++ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0848, 0x0844, 0x0840, 0x01ef, ++ 0x01f0, ++ 0x01f0, ++ }, ++ { ++ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x084c, 0x0848, 0x0844, 0x01ee, ++ 0x01ef, ++ 0x01f0, ++ }, ++ { ++ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0850, 0x084c, 0x0848, 0x01ed, ++ 0x01ee, ++ 0x01ef, ++ }, ++ { ++ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0854, 0x0850, 0x084c, 0x01ec, ++ 0x01ed, ++ 0x01ee, ++ }, ++ { ++ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, ++ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0858, 0x0854, 0x0850, 0x01eb, ++ 0x01ec, ++ 0x01ed, ++ }, ++ { ++ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x085c, 0x0858, 0x0854, 0x01ea, ++ 0x01eb, ++ 0x01ec, ++ }, ++ { ++ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0860, 0x085c, 0x0858, 0x01e9, ++ 0x01ea, ++ 0x01eb, ++ }, ++ { ++ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0864, 0x0860, 0x085c, 0x01e8, ++ 0x01e9, ++ 0x01ea, ++ }, ++ { ++ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0868, 0x0864, 0x0860, 0x01e7, ++ 0x01e8, ++ 0x01e9, ++ }, ++ { ++ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x086c, 0x0868, 0x0864, 0x01e6, ++ 0x01e7, ++ 0x01e8, ++ }, ++ { ++ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x00, ++ 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x0870, 0x086c, 0x0868, 0x01e5, ++ 0x01e6, ++ 0x01e7, ++ }, ++ { ++ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0874, 0x0870, 0x086c, 0x01e5, ++ 0x01e5, ++ 0x01e6, ++ }, ++ { ++ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0878, 0x0874, 0x0870, 0x01e4, ++ 0x01e5, ++ 0x01e5, ++ }, ++ { ++ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x087c, 0x0878, 0x0874, 0x01e3, ++ 0x01e4, ++ 0x01e5, ++ }, ++ { ++ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0880, 0x087c, 0x0878, 0x01e2, ++ 0x01e3, ++ 0x01e4, ++ }, ++ { ++ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0884, 0x0880, 0x087c, 0x01e1, ++ 0x01e2, ++ 0x01e3, ++ }, ++ { ++ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, ++ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0888, 0x0884, 0x0880, 0x01e0, ++ 0x01e1, ++ 0x01e2, ++ }, ++ { ++ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x00, ++ 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x088c, 0x0888, 0x0884, 0x01df, ++ 0x01e0, ++ 0x01e1, ++ }, ++ { ++ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x0890, 0x088c, 0x0888, 0x01de, ++ 0x01df, ++ 0x01e0, ++ }, ++ { ++ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0894, 0x0890, 0x088c, 0x01dd, ++ 0x01de, ++ 0x01df, ++ }, ++ { ++ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0898, 0x0894, 0x0890, 0x01dd, ++ 0x01dd, ++ 0x01de, ++ }, ++ { ++ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x089c, 0x0898, 0x0894, 0x01dc, ++ 0x01dd, ++ 0x01dd, ++ }, ++ { ++ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x08a0, 0x089c, 0x0898, 0x01db, ++ 0x01dc, ++ 0x01dd, ++ }, ++ { ++ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a4, 0x08a0, 0x089c, 0x01da, ++ 0x01db, ++ 0x01dc, ++ }, ++ { ++ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a8, 0x08a4, 0x08a0, 0x01d9, ++ 0x01da, ++ 0x01db, ++ }, ++ { ++ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08ac, 0x08a8, 0x08a4, 0x01d8, ++ 0x01d9, ++ 0x01da, ++ }, ++ { ++ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b0, 0x08ac, 0x08a8, 0x01d7, ++ 0x01d8, ++ 0x01d9, ++ }, ++ { ++ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b4, 0x08b0, 0x08ac, 0x01d7, ++ 0x01d7, ++ 0x01d8, ++ }, ++ { ++ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, ++ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b8, 0x08b4, 0x08b0, 0x01d6, ++ 0x01d7, ++ 0x01d7, ++ }, ++ { ++ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x00, ++ 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x08bc, 0x08b8, 0x08b4, 0x01d5, ++ 0x01d6, ++ 0x01d7, ++ }, ++ { ++ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x00, ++ 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x08c0, 0x08bc, 0x08b8, 0x01d4, ++ 0x01d5, ++ 0x01d6, ++ }, ++ { ++ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x00, ++ 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x08c4, 0x08c0, 0x08bc, 0x01d3, ++ 0x01d4, ++ 0x01d5, ++ }, ++ { ++ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08c8, 0x08c4, 0x08c0, 0x01d2, ++ 0x01d3, ++ 0x01d4, ++ }, ++ { ++ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08cc, 0x08c8, 0x08c4, 0x01d2, ++ 0x01d2, ++ 0x01d3, ++ }, ++ { ++ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d0, 0x08cc, 0x08c8, 0x01d1, ++ 0x01d2, ++ 0x01d2, ++ }, ++ { ++ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d4, 0x08d0, 0x08cc, 0x01d0, ++ 0x01d1, ++ 0x01d2, ++ }, ++ { ++ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08d8, 0x08d4, 0x08d0, 0x01cf, ++ 0x01d0, ++ 0x01d1, ++ }, ++ { ++ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00, ++ 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08dc, 0x08d8, 0x08d4, 0x01ce, ++ 0x01cf, ++ 0x01d0, ++ }, ++ { ++ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, ++ 0x01ce, ++ 0x01cf, ++ }, ++ { ++ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, ++ 0x01ce, ++ 0x01ce, ++ }, ++ { ++ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, ++ 0x01cd, ++ 0x01ce, ++ }, ++ { ++ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, ++ 0x01cc, ++ 0x01cd, ++ }, ++ { ++ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, ++ 0x01cb, ++ 0x01cc, ++ }, ++ { ++ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, ++ 0x01ca, ++ 0x01cb, ++ }, ++ { ++ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, ++ 0x01ca, ++ 0x01cb, ++ }, ++ { ++ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, ++ 0x01c9, ++ 0x01ca, ++ }, ++ { ++ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, ++ 0x01c9, ++ 0x01ca, ++ }, ++ { ++ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, ++ 0x01c9, ++ 0x01c9, ++ }, ++ { ++ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, ++ 0x01c8, ++ 0x01c9, ++ }, ++ { ++ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, ++ 0x01c8, ++ 0x01c9, ++ }, ++ { ++ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, ++ 0x01c8, ++ 0x01c8, ++ }, ++ { ++ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, ++ 0x01c7, ++ 0x01c8, ++ }, ++ { ++ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, ++ 0x01c7, ++ 0x01c8, ++ }, ++ { ++ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, ++ 0x01c6, ++ 0x01c7, ++ }, ++ { ++ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, ++ 0x01c6, ++ 0x01c7, ++ }, ++ { ++ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, ++ 0x01c6, ++ 0x01c6, ++ }, ++ { ++ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, ++ 0x01c5, ++ 0x01c6, ++ }, ++ { ++ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, ++ 0x01c5, ++ 0x01c6, ++ }, ++ { ++ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, ++ 0x01c4, ++ 0x01c5, ++ }, ++ { ++ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, ++ 0x01c4, ++ 0x01c5, ++ }, ++ { ++ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, ++ 0x01c4, ++ 0x01c4, ++ }, ++ { ++ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, ++ 0x01c3, ++ 0x01c4, ++ }, ++ { ++ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, ++ 0x01c3, ++ 0x01c4, ++ }, ++ { ++ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, ++ 0x01c2, ++ 0x01c3, ++ }, ++ { ++ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, ++ 0x01c2, ++ 0x01c3, ++ }, ++ { ++ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, ++ 0x01c2, ++ 0x01c2, ++ }, ++ { ++ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, ++ 0x01c1, ++ 0x01c2, ++ }, ++ { ++ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, ++ 0x01c0, ++ 0x01c1, ++ }, ++ { ++ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, ++ 0x01bf, ++ 0x01c0, ++ }, ++ { ++ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, ++ 0x01bf, ++ 0x01bf, ++ }, ++ { ++ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, ++ 0x01be, ++ 0x01bf, ++ }, ++ { ++ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, ++ 0x01bd, ++ 0x01be, ++ }, ++ { ++ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, ++ 0x01bc, ++ 0x01bd, ++ }, ++ { ++ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, ++ 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, ++ 0x043f, ++ 0x0443, ++ }, ++ { ++ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, ++ 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, ++ 0x043d, ++ 0x0441, ++ }, ++ { ++ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, ++ 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, ++ 0x043a, ++ 0x043f, ++ }, ++ { ++ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, ++ 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, ++ 0x0438, ++ 0x043d, ++ }, ++ { ++ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, ++ 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, ++ 0x0436, ++ 0x043a, ++ }, ++ { ++ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, ++ 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, ++ 0x0434, ++ 0x0438, ++ }, ++ { ++ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x51, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, ++ 0x0431, ++ 0x0436, ++ }, ++ { ++ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, ++ 0x042f, ++ 0x0434, ++ }, ++ { ++ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, ++ 0x042d, ++ 0x0431, ++ }, ++ { ++ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, ++ 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, ++ 0x042b, ++ 0x042f, ++ }, ++ { ++ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, ++ 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, ++ 0x0429, ++ 0x042d, ++ }, ++ { ++ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11, ++ 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, ++ 0x0427, ++ 0x042b, ++ }, ++ { ++ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11, ++ 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, ++ 0x0424, ++ 0x0429, ++ }, ++ { ++ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, ++ 0x04, 0x00, 0x04, 0x00, 0x11, 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x11, ++ 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, ++ 0x041f, ++ 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio2057_rev5 ++chan_info_nphyrev8_2057_rev5[] = { ++ { ++ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1, ++ 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3, ++ 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5, ++ 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c, ++ 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7, ++ 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c, ++ 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9, ++ 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c, ++ 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb, ++ 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd, ++ 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf, ++ 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1, ++ 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b, ++ 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3, ++ 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b, ++ 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5, ++ 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b, ++ 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7, ++ 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a, ++ 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9, ++ 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a, ++ 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de, ++ 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio2057_rev5 ++chan_info_nphyrev9_2057_rev5v1[] = { ++ { ++ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1, ++ 0x043a, 0x043f, 0x0443}, ++ { ++ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3, ++ 0x0438, 0x043d, 0x0441}, ++ { ++ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d, ++ 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5, ++ 0x0436, 0x043a, 0x043f}, ++ { ++ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c, ++ 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7, ++ 0x0434, 0x0438, 0x043d}, ++ { ++ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c, ++ 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9, ++ 0x0431, 0x0436, 0x043a}, ++ { ++ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c, ++ 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb, ++ 0x042f, 0x0434, 0x0438}, ++ { ++ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd, ++ 0x042d, 0x0431, 0x0436}, ++ { ++ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf, ++ 0x042b, 0x042f, 0x0434}, ++ { ++ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b, ++ 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1, ++ 0x0429, 0x042d, 0x0431}, ++ { ++ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b, ++ 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3, ++ 0x0427, 0x042b, 0x042f}, ++ { ++ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b, ++ 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5, ++ 0x0424, 0x0429, 0x042d}, ++ { ++ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b, ++ 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7, ++ 0x0422, 0x0427, 0x042b}, ++ { ++ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a, ++ 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9, ++ 0x0420, 0x0424, 0x0429}, ++ { ++ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a, ++ 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de, ++ 0x041b, 0x041f, 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = { ++ { ++ 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b4, 0x07b0, 0x07ac, 0x0214, ++ 0x0215, ++ 0x0216}, ++ { ++ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213, ++ 0x0214, ++ 0x0215}, ++ { ++ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212, ++ 0x0213, ++ 0x0214}, ++ { ++ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211, ++ 0x0212, ++ 0x0213}, ++ { ++ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f, ++ 0x0211, ++ 0x0212}, ++ { ++ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e, ++ 0x020f, ++ 0x0211}, ++ { ++ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d, ++ 0x020e, ++ 0x020f}, ++ { ++ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c, ++ 0x020d, ++ 0x020e}, ++ { ++ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b, ++ 0x020c, ++ 0x020d}, ++ { ++ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a, ++ 0x020b, ++ 0x020c}, ++ { ++ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209, ++ 0x020a, ++ 0x020b}, ++ { ++ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208, ++ 0x0209, ++ 0x020a}, ++ { ++ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207, ++ 0x0208, ++ 0x0209}, ++ { ++ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206, ++ 0x0207, ++ 0x0208}, ++ { ++ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205, ++ 0x0206, ++ 0x0207}, ++ { ++ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204, ++ 0x0205, ++ 0x0206}, ++ { ++ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203, ++ 0x0204, ++ 0x0205}, ++ { ++ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202, ++ 0x0203, ++ 0x0204}, ++ { ++ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201, ++ 0x0202, ++ 0x0203}, ++ { ++ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200, ++ 0x0201, ++ 0x0202}, ++ { ++ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff, ++ 0x0200, ++ 0x0201}, ++ { ++ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe, ++ 0x01ff, ++ 0x0200}, ++ { ++ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd, ++ 0x01fe, ++ 0x01ff}, ++ { ++ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb, ++ 0x01fc, ++ 0x01fd}, ++ { ++ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa, ++ 0x01fb, ++ 0x01fc}, ++ { ++ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9, ++ 0x01fa, ++ 0x01fb}, ++ { ++ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8, ++ 0x01f9, ++ 0x01fa}, ++ { ++ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7, ++ 0x01f8, ++ 0x01f9}, ++ { ++ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6, ++ 0x01f7, ++ 0x01f8}, ++ { ++ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5, ++ 0x01f6, ++ 0x01f7}, ++ { ++ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4, ++ 0x01f5, ++ 0x01f6}, ++ { ++ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3, ++ 0x01f4, ++ 0x01f5}, ++ { ++ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2, ++ 0x01f3, ++ 0x01f4}, ++ { ++ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1, ++ 0x01f2, ++ 0x01f3}, ++ { ++ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0, ++ 0x01f1, ++ 0x01f2}, ++ { ++ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0, ++ 0x01f0, ++ 0x01f1}, ++ { ++ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef, ++ 0x01f0, ++ 0x01f0}, ++ { ++ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee, ++ 0x01ef, ++ 0x01f0}, ++ { ++ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed, ++ 0x01ee, ++ 0x01ef}, ++ { ++ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec, ++ 0x01ed, ++ 0x01ee}, ++ { ++ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb, ++ 0x01ec, ++ 0x01ed}, ++ { ++ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea, ++ 0x01eb, ++ 0x01ec}, ++ { ++ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9, ++ 0x01ea, ++ 0x01eb}, ++ { ++ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8, ++ 0x01e9, ++ 0x01ea}, ++ { ++ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7, ++ 0x01e8, ++ 0x01e9}, ++ { ++ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6, ++ 0x01e7, ++ 0x01e8}, ++ { ++ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5, ++ 0x01e6, ++ 0x01e7}, ++ { ++ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5, ++ 0x01e5, ++ 0x01e6}, ++ { ++ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4, ++ 0x01e5, ++ 0x01e5}, ++ { ++ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3, ++ 0x01e4, ++ 0x01e5}, ++ { ++ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2, ++ 0x01e3, ++ 0x01e4}, ++ { ++ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1, ++ 0x01e2, ++ 0x01e3}, ++ { ++ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0, ++ 0x01e1, ++ 0x01e2}, ++ { ++ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df, ++ 0x01e0, ++ 0x01e1}, ++ { ++ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de, ++ 0x01df, ++ 0x01e0}, ++ { ++ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd, ++ 0x01de, ++ 0x01df}, ++ { ++ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd, ++ 0x01dd, ++ 0x01de}, ++ { ++ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc, ++ 0x01dd, ++ 0x01dd}, ++ { ++ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db, ++ 0x01dc, ++ 0x01dd}, ++ { ++ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da, ++ 0x01db, ++ 0x01dc}, ++ { ++ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9, ++ 0x01da, ++ 0x01db}, ++ { ++ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8, ++ 0x01d9, ++ 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7, ++ 0x01d8, ++ 0x01d9}, ++ { ++ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7, ++ 0x01d7, ++ 0x01d8}, ++ { ++ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6, ++ 0x01d7, ++ 0x01d7}, ++ { ++ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5, ++ 0x01d6, ++ 0x01d7}, ++ { ++ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4, ++ 0x01d5, ++ 0x01d6}, ++ { ++ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3, ++ 0x01d4, ++ 0x01d5}, ++ { ++ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2, ++ 0x01d3, ++ 0x01d4}, ++ { ++ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2, ++ 0x01d2, ++ 0x01d3}, ++ { ++ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1, ++ 0x01d2, ++ 0x01d2}, ++ { ++ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0, ++ 0x01d1, ++ 0x01d2}, ++ { ++ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf, ++ 0x01d0, ++ 0x01d1}, ++ { ++ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce, ++ 0x01cf, ++ 0x01d0}, ++ { ++ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce, ++ 0x01ce, ++ 0x01cf}, ++ { ++ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd, ++ 0x01ce, ++ 0x01ce}, ++ { ++ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc, ++ 0x01cd, ++ 0x01ce}, ++ { ++ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb, ++ 0x01cc, ++ 0x01cd}, ++ { ++ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca, ++ 0x01cb, ++ 0x01cc}, ++ { ++ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9, ++ 0x01ca, ++ 0x01cb}, ++ { ++ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9, ++ 0x01ca, ++ 0x01cb}, ++ { ++ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9, ++ 0x01c9, ++ 0x01ca}, ++ { ++ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8, ++ 0x01c9, ++ 0x01ca}, ++ { ++ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8, ++ 0x01c9, ++ 0x01c9}, ++ { ++ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8, ++ 0x01c8, ++ 0x01c9}, ++ { ++ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, ++ 0x01c8, ++ 0x01c9}, ++ { ++ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, ++ 0x01c8, ++ 0x01c8}, ++ { ++ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, ++ 0x01c7, ++ 0x01c8}, ++ { ++ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, ++ 0x01c7, ++ 0x01c8}, ++ { ++ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, ++ 0x01c6, ++ 0x01c7}, ++ { ++ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, ++ 0x01c6, ++ 0x01c7}, ++ { ++ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, ++ 0x01c6, ++ 0x01c6}, ++ { ++ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, ++ 0x01c5, ++ 0x01c6}, ++ { ++ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, ++ 0x01c5, ++ 0x01c6}, ++ { ++ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, ++ 0x01c4, ++ 0x01c5}, ++ { ++ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, ++ 0x01c4, ++ 0x01c5}, ++ { ++ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, ++ 0x01c4, ++ 0x01c4}, ++ { ++ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, ++ 0x01c3, ++ 0x01c4}, ++ { ++ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, ++ 0x01c3, ++ 0x01c4}, ++ { ++ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, ++ 0x01c2, ++ 0x01c3}, ++ { ++ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, ++ 0x01c2, ++ 0x01c3}, ++ { ++ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, ++ 0x01c2, ++ 0x01c2}, ++ { ++ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, ++ 0x01c1, ++ 0x01c2}, ++ { ++ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, ++ 0x01c0, ++ 0x01c1}, ++ { ++ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, ++ 0x01bf, ++ 0x01c0}, ++ { ++ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, ++ 0x01bf, ++ 0x01bf}, ++ { ++ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, ++ 0x01be, ++ 0x01bf}, ++ { ++ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, ++ 0x01bd, ++ 0x01be}, ++ { ++ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, ++ 0x01bc, ++ 0x01bd}, ++ { ++ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, ++ 0x043f, ++ 0x0443}, ++ { ++ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, ++ 0x043d, ++ 0x0441}, ++ { ++ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, ++ 0x043a, ++ 0x043f}, ++ { ++ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, ++ 0x0438, ++ 0x043d}, ++ { ++ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, ++ 0x0436, ++ 0x043a}, ++ { ++ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, ++ 0x0434, ++ 0x0438}, ++ { ++ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, ++ 0x0431, ++ 0x0436}, ++ { ++ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, ++ 0x042f, ++ 0x0434}, ++ { ++ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, ++ 0x042d, ++ 0x0431}, ++ { ++ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, ++ 0x042b, ++ 0x042f}, ++ { ++ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, ++ 0x0429, ++ 0x042d}, ++ { ++ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, ++ 0x0427, ++ 0x042b}, ++ { ++ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, ++ 0x0424, ++ 0x0429}, ++ { ++ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, ++ 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, ++ 0x041f, ++ 0x0424} ++}; ++ ++static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = { ++ { ++ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213, ++ 0x0214, ++ 0x0215}, ++ { ++ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212, ++ 0x0213, ++ 0x0214}, ++ { ++ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211, ++ 0x0212, ++ 0x0213}, ++ { ++ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f, ++ 0x0211, ++ 0x0212}, ++ { ++ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e, ++ 0x020f, ++ 0x0211}, ++ { ++ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d, ++ 0x020e, ++ 0x020f}, ++ { ++ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c, ++ 0x020d, ++ 0x020e}, ++ { ++ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b, ++ 0x020c, ++ 0x020d}, ++ { ++ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, ++ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a, ++ 0x020b, ++ 0x020c}, ++ { ++ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209, ++ 0x020a, ++ 0x020b}, ++ { ++ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208, ++ 0x0209, ++ 0x020a}, ++ { ++ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207, ++ 0x0208, ++ 0x0209}, ++ { ++ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206, ++ 0x0207, ++ 0x0208}, ++ { ++ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205, ++ 0x0206, ++ 0x0207}, ++ { ++ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204, ++ 0x0205, ++ 0x0206}, ++ { ++ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203, ++ 0x0204, ++ 0x0205}, ++ { ++ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, ++ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, ++ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202, ++ 0x0203, ++ 0x0204}, ++ { ++ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201, ++ 0x0202, ++ 0x0203}, ++ { ++ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200, ++ 0x0201, ++ 0x0202}, ++ { ++ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff, ++ 0x0200, ++ 0x0201}, ++ { ++ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe, ++ 0x01ff, ++ 0x0200}, ++ { ++ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd, ++ 0x01fe, ++ 0x01ff}, ++ { ++ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb, ++ 0x01fc, ++ 0x01fd}, ++ { ++ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, ++ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa, ++ 0x01fb, ++ 0x01fc}, ++ { ++ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9, ++ 0x01fa, ++ 0x01fb}, ++ { ++ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, ++ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8, ++ 0x01f9, ++ 0x01fa}, ++ { ++ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7, ++ 0x01f8, ++ 0x01f9}, ++ { ++ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6, ++ 0x01f7, ++ 0x01f8}, ++ { ++ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5, ++ 0x01f6, ++ 0x01f7}, ++ { ++ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4, ++ 0x01f5, ++ 0x01f6}, ++ { ++ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3, ++ 0x01f4, ++ 0x01f5}, ++ { ++ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, ++ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2, ++ 0x01f3, ++ 0x01f4}, ++ { ++ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1, ++ 0x01f2, ++ 0x01f3}, ++ { ++ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0, ++ 0x01f1, ++ 0x01f2}, ++ { ++ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0, ++ 0x01f0, ++ 0x01f1}, ++ { ++ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, ++ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef, ++ 0x01f0, ++ 0x01f0}, ++ { ++ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee, ++ 0x01ef, ++ 0x01f0}, ++ { ++ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed, ++ 0x01ee, ++ 0x01ef}, ++ { ++ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec, ++ 0x01ed, ++ 0x01ee}, ++ { ++ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, ++ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb, ++ 0x01ec, ++ 0x01ed}, ++ { ++ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea, ++ 0x01eb, ++ 0x01ec}, ++ { ++ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9, ++ 0x01ea, ++ 0x01eb}, ++ { ++ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8, ++ 0x01e9, ++ 0x01ea}, ++ { ++ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7, ++ 0x01e8, ++ 0x01e9}, ++ { ++ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6, ++ 0x01e7, ++ 0x01e8}, ++ { ++ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, ++ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5, ++ 0x01e6, ++ 0x01e7}, ++ { ++ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5, ++ 0x01e5, ++ 0x01e6}, ++ { ++ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, ++ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4, ++ 0x01e5, ++ 0x01e5}, ++ { ++ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3, ++ 0x01e4, ++ 0x01e5}, ++ { ++ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2, ++ 0x01e3, ++ 0x01e4}, ++ { ++ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1, ++ 0x01e2, ++ 0x01e3}, ++ { ++ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0, ++ 0x01e1, ++ 0x01e2}, ++ { ++ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df, ++ 0x01e0, ++ 0x01e1}, ++ { ++ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de, ++ 0x01df, ++ 0x01e0}, ++ { ++ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd, ++ 0x01de, ++ 0x01df}, ++ { ++ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, ++ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd, ++ 0x01dd, ++ 0x01de}, ++ { ++ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc, ++ 0x01dd, ++ 0x01dd}, ++ { ++ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, ++ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db, ++ 0x01dc, ++ 0x01dd}, ++ { ++ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da, ++ 0x01db, ++ 0x01dc}, ++ { ++ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9, ++ 0x01da, ++ 0x01db}, ++ { ++ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8, ++ 0x01d9, ++ 0x01da}, ++ { ++ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7, ++ 0x01d8, ++ 0x01d9}, ++ { ++ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7, ++ 0x01d7, ++ 0x01d8}, ++ { ++ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6, ++ 0x01d7, ++ 0x01d7}, ++ { ++ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5, ++ 0x01d6, ++ 0x01d7}, ++ { ++ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, ++ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4, ++ 0x01d5, ++ 0x01d6}, ++ { ++ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3, ++ 0x01d4, ++ 0x01d5}, ++ { ++ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, ++ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2, ++ 0x01d3, ++ 0x01d4}, ++ { ++ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2, ++ 0x01d2, ++ 0x01d3}, ++ { ++ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1, ++ 0x01d2, ++ 0x01d2}, ++ { ++ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0, ++ 0x01d1, ++ 0x01d2}, ++ { ++ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf, ++ 0x01d0, ++ 0x01d1}, ++ { ++ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce, ++ 0x01cf, ++ 0x01d0}, ++ { ++ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce, ++ 0x01ce, ++ 0x01cf}, ++ { ++ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd, ++ 0x01ce, ++ 0x01ce}, ++ { ++ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, ++ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc, ++ 0x01cd, ++ 0x01ce}, ++ { ++ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb, ++ 0x01cc, ++ 0x01cd}, ++ { ++ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca, ++ 0x01cb, ++ 0x01cc}, ++ { ++ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, ++ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9, ++ 0x01ca, ++ 0x01cb}, ++ { ++ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9, ++ 0x01ca, ++ 0x01cb}, ++ { ++ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9, ++ 0x01c9, ++ 0x01ca}, ++ { ++ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8, ++ 0x01c9, ++ 0x01ca}, ++ { ++ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8, ++ 0x01c9, ++ 0x01c9}, ++ { ++ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8, ++ 0x01c8, ++ 0x01c9}, ++ { ++ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, ++ 0x01c8, ++ 0x01c9}, ++ { ++ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, ++ 0x01c8, ++ 0x01c8}, ++ { ++ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, ++ 0x01c7, ++ 0x01c8}, ++ { ++ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, ++ 0x01c7, ++ 0x01c8}, ++ { ++ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, ++ 0x01c6, ++ 0x01c7}, ++ { ++ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, ++ 0x01c6, ++ 0x01c7}, ++ { ++ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, ++ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, ++ 0x01c6, ++ 0x01c6}, ++ { ++ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, ++ 0x01c5, ++ 0x01c6}, ++ { ++ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, ++ 0x01c5, ++ 0x01c6}, ++ { ++ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, ++ 0x01c4, ++ 0x01c5}, ++ { ++ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, ++ 0x01c4, ++ 0x01c5}, ++ { ++ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, ++ 0x01c4, ++ 0x01c4}, ++ { ++ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, ++ 0x01c3, ++ 0x01c4}, ++ { ++ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, ++ 0x01c3, ++ 0x01c4}, ++ { ++ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, ++ 0x01c2, ++ 0x01c3}, ++ { ++ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, ++ 0x01c2, ++ 0x01c3}, ++ { ++ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, ++ 0x01c2, ++ 0x01c2}, ++ { ++ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, ++ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, ++ 0x01c1, ++ 0x01c2}, ++ { ++ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, ++ 0x01c0, ++ 0x01c1}, ++ { ++ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, ++ 0x01bf, ++ 0x01c0}, ++ { ++ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, ++ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, ++ 0x01bf, ++ 0x01bf}, ++ { ++ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, ++ 0x01be, ++ 0x01bf}, ++ { ++ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, ++ 0x01bd, ++ 0x01be}, ++ { ++ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, ++ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, ++ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, ++ 0x01bc, ++ 0x01bd}, ++ { ++ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, ++ 0x043f, ++ 0x0443}, ++ { ++ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, ++ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, ++ 0x043d, ++ 0x0441}, ++ { ++ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, ++ 0x043a, ++ 0x043f}, ++ { ++ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, ++ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, ++ 0x0438, ++ 0x043d}, ++ { ++ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, ++ 0x0436, ++ 0x043a}, ++ { ++ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, ++ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, ++ 0x0434, ++ 0x0438}, ++ { ++ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, ++ 0x0431, ++ 0x0436}, ++ { ++ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, ++ 0x042f, ++ 0x0434}, ++ { ++ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, ++ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, ++ 0x042d, ++ 0x0431}, ++ { ++ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, ++ 0x042b, ++ 0x042f}, ++ { ++ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, ++ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, ++ 0x0429, ++ 0x042d}, ++ { ++ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, ++ 0x0427, ++ 0x042b}, ++ { ++ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, ++ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, ++ 0x0424, ++ 0x0429}, ++ { ++ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, ++ 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61, ++ 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, ++ 0x041f, ++ 0x0424} ++}; ++ ++static struct radio_regs regs_2055[] = { ++ {0x02, 0x80, 0x80, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0x27, 0x27, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0x27, 0x27, 0, 0}, ++ {0x07, 0x7f, 0x7f, 1, 1}, ++ {0x08, 0x7, 0x7, 1, 1}, ++ {0x09, 0x7f, 0x7f, 1, 1}, ++ {0x0A, 0x7, 0x7, 1, 1}, ++ {0x0B, 0x15, 0x15, 0, 0}, ++ {0x0C, 0x15, 0x15, 0, 0}, ++ {0x0D, 0x4f, 0x4f, 1, 1}, ++ {0x0E, 0x5, 0x5, 1, 1}, ++ {0x0F, 0x4f, 0x4f, 1, 1}, ++ {0x10, 0x5, 0x5, 1, 1}, ++ {0x11, 0xd0, 0xd0, 0, 0}, ++ {0x12, 0x2, 0x2, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0x40, 0x40, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0xc0, 0xc0, 0, 0}, ++ {0x1E, 0xff, 0xff, 0, 0}, ++ {0x1F, 0xc0, 0xc0, 0, 0}, ++ {0x20, 0xff, 0xff, 0, 0}, ++ {0x21, 0xc0, 0xc0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x2c, 0x2c, 0, 0}, ++ {0x24, 0, 0, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0xa4, 0xa4, 0, 0}, ++ {0x2E, 0x38, 0x38, 0, 0}, ++ {0x2F, 0, 0, 0, 0}, ++ {0x30, 0x4, 0x4, 1, 1}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0xa, 0xa, 0, 0}, ++ {0x33, 0x87, 0x87, 0, 0}, ++ {0x34, 0x9, 0x9, 0, 0}, ++ {0x35, 0x70, 0x70, 0, 0}, ++ {0x36, 0x11, 0x11, 0, 0}, ++ {0x37, 0x18, 0x18, 1, 1}, ++ {0x38, 0x6, 0x6, 0, 0}, ++ {0x39, 0x4, 0x4, 1, 1}, ++ {0x3A, 0x6, 0x6, 0, 0}, ++ {0x3B, 0x9e, 0x9e, 0, 0}, ++ {0x3C, 0x9, 0x9, 0, 0}, ++ {0x3D, 0xc8, 0xc8, 1, 1}, ++ {0x3E, 0x88, 0x88, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0, 0, 0, 0}, ++ {0x42, 0x1, 0x1, 0, 0}, ++ {0x43, 0x2, 0x2, 0, 0}, ++ {0x44, 0x96, 0x96, 0, 0}, ++ {0x45, 0x3e, 0x3e, 0, 0}, ++ {0x46, 0x3e, 0x3e, 0, 0}, ++ {0x47, 0x13, 0x13, 0, 0}, ++ {0x48, 0x2, 0x2, 0, 0}, ++ {0x49, 0x15, 0x15, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0, 0, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0, 0, 0, 0}, ++ {0x50, 0x8, 0x8, 0, 0}, ++ {0x51, 0x8, 0x8, 0, 0}, ++ {0x52, 0x6, 0x6, 0, 0}, ++ {0x53, 0x84, 0x84, 1, 1}, ++ {0x54, 0xc3, 0xc3, 0, 0}, ++ {0x55, 0x8f, 0x8f, 0, 0}, ++ {0x56, 0xff, 0xff, 0, 0}, ++ {0x57, 0xff, 0xff, 0, 0}, ++ {0x58, 0x88, 0x88, 0, 0}, ++ {0x59, 0x88, 0x88, 0, 0}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0xcc, 0xcc, 0, 0}, ++ {0x5C, 0x6, 0x6, 0, 0}, ++ {0x5D, 0x80, 0x80, 0, 0}, ++ {0x5E, 0x80, 0x80, 0, 0}, ++ {0x5F, 0xf8, 0xf8, 0, 0}, ++ {0x60, 0x88, 0x88, 0, 0}, ++ {0x61, 0x88, 0x88, 0, 0}, ++ {0x62, 0x88, 0x8, 1, 1}, ++ {0x63, 0x88, 0x88, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0x1, 0x1, 1, 1}, ++ {0x66, 0x8a, 0x8a, 0, 0}, ++ {0x67, 0x8, 0x8, 0, 0}, ++ {0x68, 0x83, 0x83, 0, 0}, ++ {0x69, 0x6, 0x6, 0, 0}, ++ {0x6A, 0xa0, 0xa0, 0, 0}, ++ {0x6B, 0xa, 0xa, 0, 0}, ++ {0x6C, 0x87, 0x87, 1, 1}, ++ {0x6D, 0x2a, 0x2a, 0, 0}, ++ {0x6E, 0x2a, 0x2a, 0, 0}, ++ {0x6F, 0x2a, 0x2a, 0, 0}, ++ {0x70, 0x2a, 0x2a, 0, 0}, ++ {0x71, 0x18, 0x18, 0, 0}, ++ {0x72, 0x6a, 0x6a, 1, 1}, ++ {0x73, 0xab, 0xab, 1, 1}, ++ {0x74, 0x13, 0x13, 1, 1}, ++ {0x75, 0xc1, 0xc1, 1, 1}, ++ {0x76, 0xaa, 0xaa, 1, 1}, ++ {0x77, 0x87, 0x87, 1, 1}, ++ {0x78, 0, 0, 0, 0}, ++ {0x79, 0x6, 0x6, 0, 0}, ++ {0x7A, 0x7, 0x7, 0, 0}, ++ {0x7B, 0x7, 0x7, 0, 0}, ++ {0x7C, 0x15, 0x15, 0, 0}, ++ {0x7D, 0x55, 0x55, 0, 0}, ++ {0x7E, 0x97, 0x97, 1, 1}, ++ {0x7F, 0x8, 0x8, 0, 0}, ++ {0x80, 0x14, 0x14, 1, 1}, ++ {0x81, 0x33, 0x33, 0, 0}, ++ {0x82, 0x88, 0x88, 0, 0}, ++ {0x83, 0x6, 0x6, 0, 0}, ++ {0x84, 0x3, 0x3, 1, 1}, ++ {0x85, 0xa, 0xa, 0, 0}, ++ {0x86, 0x3, 0x3, 1, 1}, ++ {0x87, 0x2a, 0x2a, 0, 0}, ++ {0x88, 0xa4, 0xa4, 0, 0}, ++ {0x89, 0x18, 0x18, 0, 0}, ++ {0x8A, 0x28, 0x28, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0x4a, 0x4a, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0xf8, 0xf8, 0, 0}, ++ {0x8F, 0x88, 0x88, 0, 0}, ++ {0x90, 0x88, 0x88, 0, 0}, ++ {0x91, 0x88, 0x8, 1, 1}, ++ {0x92, 0x88, 0x88, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0x1, 0x1, 1, 1}, ++ {0x95, 0x8a, 0x8a, 0, 0}, ++ {0x96, 0x8, 0x8, 0, 0}, ++ {0x97, 0x83, 0x83, 0, 0}, ++ {0x98, 0x6, 0x6, 0, 0}, ++ {0x99, 0xa0, 0xa0, 0, 0}, ++ {0x9A, 0xa, 0xa, 0, 0}, ++ {0x9B, 0x87, 0x87, 1, 1}, ++ {0x9C, 0x2a, 0x2a, 0, 0}, ++ {0x9D, 0x2a, 0x2a, 0, 0}, ++ {0x9E, 0x2a, 0x2a, 0, 0}, ++ {0x9F, 0x2a, 0x2a, 0, 0}, ++ {0xA0, 0x18, 0x18, 0, 0}, ++ {0xA1, 0x6a, 0x6a, 1, 1}, ++ {0xA2, 0xab, 0xab, 1, 1}, ++ {0xA3, 0x13, 0x13, 1, 1}, ++ {0xA4, 0xc1, 0xc1, 1, 1}, ++ {0xA5, 0xaa, 0xaa, 1, 1}, ++ {0xA6, 0x87, 0x87, 1, 1}, ++ {0xA7, 0, 0, 0, 0}, ++ {0xA8, 0x6, 0x6, 0, 0}, ++ {0xA9, 0x7, 0x7, 0, 0}, ++ {0xAA, 0x7, 0x7, 0, 0}, ++ {0xAB, 0x15, 0x15, 0, 0}, ++ {0xAC, 0x55, 0x55, 0, 0}, ++ {0xAD, 0x97, 0x97, 1, 1}, ++ {0xAE, 0x8, 0x8, 0, 0}, ++ {0xAF, 0x14, 0x14, 1, 1}, ++ {0xB0, 0x33, 0x33, 0, 0}, ++ {0xB1, 0x88, 0x88, 0, 0}, ++ {0xB2, 0x6, 0x6, 0, 0}, ++ {0xB3, 0x3, 0x3, 1, 1}, ++ {0xB4, 0xa, 0xa, 0, 0}, ++ {0xB5, 0x3, 0x3, 1, 1}, ++ {0xB6, 0x2a, 0x2a, 0, 0}, ++ {0xB7, 0xa4, 0xa4, 0, 0}, ++ {0xB8, 0x18, 0x18, 0, 0}, ++ {0xB9, 0x28, 0x28, 0, 0}, ++ {0xBA, 0, 0, 0, 0}, ++ {0xBB, 0x4a, 0x4a, 0, 0}, ++ {0xBC, 0, 0, 0, 0}, ++ {0xBD, 0x71, 0x71, 0, 0}, ++ {0xBE, 0x72, 0x72, 0, 0}, ++ {0xBF, 0x73, 0x73, 0, 0}, ++ {0xC0, 0x74, 0x74, 0, 0}, ++ {0xC1, 0x75, 0x75, 0, 0}, ++ {0xC2, 0x76, 0x76, 0, 0}, ++ {0xC3, 0x77, 0x77, 0, 0}, ++ {0xC4, 0x78, 0x78, 0, 0}, ++ {0xC5, 0x79, 0x79, 0, 0}, ++ {0xC6, 0x7a, 0x7a, 0, 0}, ++ {0xC7, 0, 0, 0, 0}, ++ {0xC8, 0, 0, 0, 0}, ++ {0xC9, 0, 0, 0, 0}, ++ {0xCA, 0, 0, 0, 0}, ++ {0xCB, 0, 0, 0, 0}, ++ {0xCC, 0, 0, 0, 0}, ++ {0xCD, 0, 0, 0, 0}, ++ {0xCE, 0x6, 0x6, 0, 0}, ++ {0xCF, 0, 0, 0, 0}, ++ {0xD0, 0, 0, 0, 0}, ++ {0xD1, 0x18, 0x18, 0, 0}, ++ {0xD2, 0x88, 0x88, 0, 0}, ++ {0xD3, 0, 0, 0, 0}, ++ {0xD4, 0, 0, 0, 0}, ++ {0xD5, 0, 0, 0, 0}, ++ {0xD6, 0, 0, 0, 0}, ++ {0xD7, 0, 0, 0, 0}, ++ {0xD8, 0, 0, 0, 0}, ++ {0xD9, 0, 0, 0, 0}, ++ {0xDA, 0x6, 0x6, 0, 0}, ++ {0xDB, 0, 0, 0, 0}, ++ {0xDC, 0, 0, 0, 0}, ++ {0xDD, 0x18, 0x18, 0, 0}, ++ {0xDE, 0x88, 0x88, 0, 0}, ++ {0xDF, 0, 0, 0, 0}, ++ {0xE0, 0, 0, 0, 0}, ++ {0xE1, 0, 0, 0, 0}, ++ {0xE2, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_SYN_2056[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0xd, 0xd, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_TX_2056[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0x11, 0x11, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0xf, 0xf, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x2d, 0x2d, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0x74, 0x74, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_RX_2056[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x99, 0x99, 0, 0}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x44, 0x44, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0x44, 0x44, 0, 0}, ++ {0x40, 0xf, 0xf, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0x50, 0x50, 1, 1}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x99, 0x99, 0, 0}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x44, 0x44, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x66, 0x66, 0, 0}, ++ {0x50, 0x66, 0x66, 0, 0}, ++ {0x51, 0x57, 0x57, 0, 0}, ++ {0x52, 0x57, 0x57, 0, 0}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x23, 0x23, 0, 0}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0x2, 0x2, 0, 0}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_SYN_2056_A1[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0xd, 0xd, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_TX_2056_A1[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0x11, 0x11, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0xf, 0xf, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x2d, 0x2d, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0x72, 0x72, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_RX_2056_A1[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x44, 0x44, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0x44, 0x44, 0, 0}, ++ {0x40, 0xf, 0xf, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0x50, 0x50, 1, 1}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x44, 0x44, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x2f, 0x2f, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_SYN_2056_rev5[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_TX_2056_rev5[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0x11, 0x11, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0xf, 0xf, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x2d, 0x2d, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0x70, 0x70, 0, 0}, ++ {0x94, 0x70, 0x70, 0, 0}, ++ {0x95, 0x71, 0x71, 1, 1}, ++ {0x96, 0x71, 0x71, 1, 1}, ++ {0x97, 0x72, 0x72, 1, 1}, ++ {0x98, 0x73, 0x73, 1, 1}, ++ {0x99, 0x74, 0x74, 1, 1}, ++ {0x9A, 0x75, 0x75, 1, 1}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_RX_2056_rev5[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x88, 0x88, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 1, 1}, ++ {0x40, 0x7, 0x7, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0, 0, 1, 1}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x4, 0x4, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_SYN_2056_rev6[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_TX_2056_rev6[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0xee, 0xee, 1, 1}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0x50, 0x50, 1, 1}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x50, 0x50, 1, 1}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0x30, 0x30, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0x70, 0x70, 0, 0}, ++ {0x94, 0x70, 0x70, 0, 0}, ++ {0x95, 0x70, 0x70, 0, 0}, ++ {0x96, 0x70, 0x70, 0, 0}, ++ {0x97, 0x70, 0x70, 0, 0}, ++ {0x98, 0x70, 0x70, 0, 0}, ++ {0x99, 0x70, 0x70, 0, 0}, ++ {0x9A, 0x70, 0x70, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_RX_2056_rev6[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x88, 0x88, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0x44, 0x44, 0, 0}, ++ {0x40, 0x7, 0x7, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x44, 0x44, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x4, 0x4, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0x5, 0x5, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0} ++}; ++ ++static struct radio_regs regs_SYN_2056_rev7[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_TX_2056_rev7[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0xee, 0xee, 1, 1}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0x50, 0x50, 1, 1}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x50, 0x50, 1, 1}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0x30, 0x30, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0x70, 0x70, 0, 0}, ++ {0x94, 0x70, 0x70, 0, 0}, ++ {0x95, 0x71, 0x71, 1, 1}, ++ {0x96, 0x71, 0x71, 1, 1}, ++ {0x97, 0x72, 0x72, 1, 1}, ++ {0x98, 0x73, 0x73, 1, 1}, ++ {0x99, 0x74, 0x74, 1, 1}, ++ {0x9A, 0x75, 0x75, 1, 1}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_RX_2056_rev7[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x88, 0x88, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 1, 1}, ++ {0x40, 0x7, 0x7, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0, 0, 1, 1}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x4, 0x4, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_SYN_2056_rev8[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x4, 0x4, 0, 0}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x30, 0x30, 0, 0}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0xd, 0xd, 0, 0}, ++ {0x4C, 0xd, 0xd, 0, 0}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x6, 0x6, 0, 0}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_TX_2056_rev8[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0xee, 0xee, 1, 1}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0x50, 0x50, 1, 1}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x50, 0x50, 1, 1}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0x30, 0x30, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0x70, 0x70, 0, 0}, ++ {0x94, 0x70, 0x70, 0, 0}, ++ {0x95, 0x70, 0x70, 0, 0}, ++ {0x96, 0x70, 0x70, 0, 0}, ++ {0x97, 0x70, 0x70, 0, 0}, ++ {0x98, 0x70, 0x70, 0, 0}, ++ {0x99, 0x70, 0x70, 0, 0}, ++ {0x9A, 0x70, 0x70, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_regs regs_RX_2056_rev8[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x88, 0x88, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0x44, 0x44, 0, 0}, ++ {0x40, 0x7, 0x7, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x44, 0x44, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x4, 0x4, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0x5, 0x5, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static const struct radio_regs regs_SYN_2056_rev11[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0x1, 0x1, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0x60, 0x60, 0, 0}, ++ {0x23, 0x6, 0x6, 0, 0}, ++ {0x24, 0xc, 0xc, 0, 0}, ++ {0x25, 0, 0, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0, 0, 0, 0}, ++ {0x28, 0x1, 0x1, 0, 0}, ++ {0x29, 0, 0, 0, 0}, ++ {0x2A, 0, 0, 0, 0}, ++ {0x2B, 0, 0, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0, 0, 0, 0}, ++ {0x2F, 0x1f, 0x1f, 0, 0}, ++ {0x30, 0x15, 0x15, 0, 0}, ++ {0x31, 0xf, 0xf, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0, 0, 0, 0}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0, 0, 0, 0}, ++ {0x38, 0, 0, 0, 0}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0, 0, 0, 0}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x13, 0x13, 0, 0}, ++ {0x3D, 0xf, 0xf, 0, 0}, ++ {0x3E, 0x18, 0x18, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x20, 0x20, 0, 0}, ++ {0x42, 0x20, 0x20, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x77, 0x77, 0, 0}, ++ {0x45, 0x7, 0x7, 0, 0}, ++ {0x46, 0x1, 0x1, 0, 0}, ++ {0x47, 0x6, 0x6, 1, 1}, ++ {0x48, 0xf, 0xf, 0, 0}, ++ {0x49, 0x3f, 0x3f, 1, 1}, ++ {0x4A, 0x32, 0x32, 0, 0}, ++ {0x4B, 0x6, 0x6, 1, 1}, ++ {0x4C, 0x6, 0x6, 1, 1}, ++ {0x4D, 0x4, 0x4, 0, 0}, ++ {0x4E, 0x2b, 0x2b, 1, 1}, ++ {0x4F, 0x1, 0x1, 0, 0}, ++ {0x50, 0x1c, 0x1c, 0, 0}, ++ {0x51, 0x2, 0x2, 0, 0}, ++ {0x52, 0x2, 0x2, 0, 0}, ++ {0x53, 0xf7, 0xf7, 1, 1}, ++ {0x54, 0xb4, 0xb4, 0, 0}, ++ {0x55, 0xd2, 0xd2, 0, 0}, ++ {0x56, 0, 0, 0, 0}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x4, 0x4, 0, 0}, ++ {0x59, 0x96, 0x96, 0, 0}, ++ {0x5A, 0x3e, 0x3e, 0, 0}, ++ {0x5B, 0x3e, 0x3e, 0, 0}, ++ {0x5C, 0x13, 0x13, 0, 0}, ++ {0x5D, 0x2, 0x2, 0, 0}, ++ {0x5E, 0, 0, 0, 0}, ++ {0x5F, 0x7, 0x7, 0, 0}, ++ {0x60, 0x7, 0x7, 1, 1}, ++ {0x61, 0x8, 0x8, 0, 0}, ++ {0x62, 0x3, 0x3, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0x40, 0x40, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0x1, 0x1, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0x60, 0x60, 0, 0}, ++ {0x71, 0x66, 0x66, 0, 0}, ++ {0x72, 0xc, 0xc, 0, 0}, ++ {0x73, 0x66, 0x66, 0, 0}, ++ {0x74, 0x8f, 0x8f, 1, 1}, ++ {0x75, 0, 0, 0, 0}, ++ {0x76, 0xcc, 0xcc, 0, 0}, ++ {0x77, 0x1, 0x1, 0, 0}, ++ {0x78, 0x66, 0x66, 0, 0}, ++ {0x79, 0x66, 0x66, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0, 0, 0, 0}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0xff, 0xff, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0x95, 0, 0, 0, 0}, ++ {0x96, 0, 0, 0, 0}, ++ {0x97, 0, 0, 0, 0}, ++ {0x98, 0, 0, 0, 0}, ++ {0x99, 0, 0, 0, 0}, ++ {0x9A, 0, 0, 0, 0}, ++ {0x9B, 0, 0, 0, 0}, ++ {0x9C, 0, 0, 0, 0}, ++ {0x9D, 0, 0, 0, 0}, ++ {0x9E, 0, 0, 0, 0}, ++ {0x9F, 0x6, 0x6, 0, 0}, ++ {0xA0, 0x66, 0x66, 0, 0}, ++ {0xA1, 0x66, 0x66, 0, 0}, ++ {0xA2, 0x66, 0x66, 0, 0}, ++ {0xA3, 0x66, 0x66, 0, 0}, ++ {0xA4, 0x66, 0x66, 0, 0}, ++ {0xA5, 0x66, 0x66, 0, 0}, ++ {0xA6, 0x66, 0x66, 0, 0}, ++ {0xA7, 0x66, 0x66, 0, 0}, ++ {0xA8, 0x66, 0x66, 0, 0}, ++ {0xA9, 0x66, 0x66, 0, 0}, ++ {0xAA, 0x66, 0x66, 0, 0}, ++ {0xAB, 0x66, 0x66, 0, 0}, ++ {0xAC, 0x66, 0x66, 0, 0}, ++ {0xAD, 0x66, 0x66, 0, 0}, ++ {0xAE, 0x66, 0x66, 0, 0}, ++ {0xAF, 0x66, 0x66, 0, 0}, ++ {0xB0, 0x66, 0x66, 0, 0}, ++ {0xB1, 0x66, 0x66, 0, 0}, ++ {0xB2, 0x66, 0x66, 0, 0}, ++ {0xB3, 0xa, 0xa, 0, 0}, ++ {0xB4, 0, 0, 0, 0}, ++ {0xB5, 0, 0, 0, 0}, ++ {0xB6, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static const struct radio_regs regs_TX_2056_rev11[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0, 0, 0, 0}, ++ {0x21, 0x88, 0x88, 0, 0}, ++ {0x22, 0x88, 0x88, 0, 0}, ++ {0x23, 0x88, 0x88, 0, 0}, ++ {0x24, 0x88, 0x88, 0, 0}, ++ {0x25, 0xc, 0xc, 0, 0}, ++ {0x26, 0, 0, 0, 0}, ++ {0x27, 0x3, 0x3, 0, 0}, ++ {0x28, 0, 0, 0, 0}, ++ {0x29, 0x3, 0x3, 0, 0}, ++ {0x2A, 0x37, 0x37, 0, 0}, ++ {0x2B, 0x3, 0x3, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0, 0, 0, 0}, ++ {0x2E, 0x1, 0x1, 0, 0}, ++ {0x2F, 0x1, 0x1, 0, 0}, ++ {0x30, 0, 0, 0, 0}, ++ {0x31, 0, 0, 0, 0}, ++ {0x32, 0, 0, 0, 0}, ++ {0x33, 0x11, 0x11, 0, 0}, ++ {0x34, 0xee, 0xee, 1, 1}, ++ {0x35, 0, 0, 0, 0}, ++ {0x36, 0, 0, 0, 0}, ++ {0x37, 0x3, 0x3, 0, 0}, ++ {0x38, 0x50, 0x50, 1, 1}, ++ {0x39, 0, 0, 0, 0}, ++ {0x3A, 0x50, 0x50, 1, 1}, ++ {0x3B, 0, 0, 0, 0}, ++ {0x3C, 0x6e, 0x6e, 0, 0}, ++ {0x3D, 0xf0, 0xf0, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0, 0, 0, 0}, ++ {0x40, 0, 0, 0, 0}, ++ {0x41, 0x3, 0x3, 0, 0}, ++ {0x42, 0x3, 0x3, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x1e, 0x1e, 0, 0}, ++ {0x45, 0, 0, 0, 0}, ++ {0x46, 0x6e, 0x6e, 0, 0}, ++ {0x47, 0xf0, 0xf0, 1, 1}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x2, 0x2, 0, 0}, ++ {0x4A, 0xff, 0xff, 1, 1}, ++ {0x4B, 0xc, 0xc, 0, 0}, ++ {0x4C, 0, 0, 0, 0}, ++ {0x4D, 0x38, 0x38, 0, 0}, ++ {0x4E, 0x70, 0x70, 1, 1}, ++ {0x4F, 0x2, 0x2, 0, 0}, ++ {0x50, 0x88, 0x88, 0, 0}, ++ {0x51, 0xc, 0xc, 0, 0}, ++ {0x52, 0, 0, 0, 0}, ++ {0x53, 0x8, 0x8, 0, 0}, ++ {0x54, 0x70, 0x70, 1, 1}, ++ {0x55, 0x2, 0x2, 0, 0}, ++ {0x56, 0xff, 0xff, 1, 1}, ++ {0x57, 0, 0, 0, 0}, ++ {0x58, 0x83, 0x83, 0, 0}, ++ {0x59, 0x77, 0x77, 1, 1}, ++ {0x5A, 0, 0, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x88, 0x88, 0, 0}, ++ {0x5D, 0, 0, 0, 0}, ++ {0x5E, 0x8, 0x8, 0, 0}, ++ {0x5F, 0x77, 0x77, 1, 1}, ++ {0x60, 0x1, 0x1, 0, 0}, ++ {0x61, 0, 0, 0, 0}, ++ {0x62, 0x7, 0x7, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0x7, 0x7, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 1, 1}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0xa, 0xa, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0, 0, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0x2, 0x2, 0, 0}, ++ {0x72, 0, 0, 0, 0}, ++ {0x73, 0, 0, 0, 0}, ++ {0x74, 0xe, 0xe, 0, 0}, ++ {0x75, 0xe, 0xe, 0, 0}, ++ {0x76, 0xe, 0xe, 0, 0}, ++ {0x77, 0x13, 0x13, 0, 0}, ++ {0x78, 0x13, 0x13, 0, 0}, ++ {0x79, 0x1b, 0x1b, 0, 0}, ++ {0x7A, 0x1b, 0x1b, 0, 0}, ++ {0x7B, 0x55, 0x55, 0, 0}, ++ {0x7C, 0x5b, 0x5b, 0, 0}, ++ {0x7D, 0x30, 0x30, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0x70, 0x70, 0, 0}, ++ {0x94, 0x70, 0x70, 0, 0}, ++ {0x95, 0x70, 0x70, 0, 0}, ++ {0x96, 0x70, 0x70, 0, 0}, ++ {0x97, 0x70, 0x70, 0, 0}, ++ {0x98, 0x70, 0x70, 0, 0}, ++ {0x99, 0x70, 0x70, 0, 0}, ++ {0x9A, 0x70, 0x70, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static const struct radio_regs regs_RX_2056_rev11[] = { ++ {0x02, 0, 0, 0, 0}, ++ {0x03, 0, 0, 0, 0}, ++ {0x04, 0, 0, 0, 0}, ++ {0x05, 0, 0, 0, 0}, ++ {0x06, 0, 0, 0, 0}, ++ {0x07, 0, 0, 0, 0}, ++ {0x08, 0, 0, 0, 0}, ++ {0x09, 0, 0, 0, 0}, ++ {0x0A, 0, 0, 0, 0}, ++ {0x0B, 0, 0, 0, 0}, ++ {0x0C, 0, 0, 0, 0}, ++ {0x0D, 0, 0, 0, 0}, ++ {0x0E, 0, 0, 0, 0}, ++ {0x0F, 0, 0, 0, 0}, ++ {0x10, 0, 0, 0, 0}, ++ {0x11, 0, 0, 0, 0}, ++ {0x12, 0, 0, 0, 0}, ++ {0x13, 0, 0, 0, 0}, ++ {0x14, 0, 0, 0, 0}, ++ {0x15, 0, 0, 0, 0}, ++ {0x16, 0, 0, 0, 0}, ++ {0x17, 0, 0, 0, 0}, ++ {0x18, 0, 0, 0, 0}, ++ {0x19, 0, 0, 0, 0}, ++ {0x1A, 0, 0, 0, 0}, ++ {0x1B, 0, 0, 0, 0}, ++ {0x1C, 0, 0, 0, 0}, ++ {0x1D, 0, 0, 0, 0}, ++ {0x1E, 0, 0, 0, 0}, ++ {0x1F, 0, 0, 0, 0}, ++ {0x20, 0x3, 0x3, 0, 0}, ++ {0x21, 0, 0, 0, 0}, ++ {0x22, 0, 0, 0, 0}, ++ {0x23, 0x90, 0x90, 0, 0}, ++ {0x24, 0x55, 0x55, 0, 0}, ++ {0x25, 0x15, 0x15, 0, 0}, ++ {0x26, 0x5, 0x5, 0, 0}, ++ {0x27, 0x15, 0x15, 0, 0}, ++ {0x28, 0x5, 0x5, 0, 0}, ++ {0x29, 0x20, 0x20, 0, 0}, ++ {0x2A, 0x11, 0x11, 0, 0}, ++ {0x2B, 0x90, 0x90, 0, 0}, ++ {0x2C, 0, 0, 0, 0}, ++ {0x2D, 0x88, 0x88, 0, 0}, ++ {0x2E, 0x32, 0x32, 0, 0}, ++ {0x2F, 0x77, 0x77, 0, 0}, ++ {0x30, 0x17, 0x17, 1, 1}, ++ {0x31, 0xff, 0xff, 1, 1}, ++ {0x32, 0x20, 0x20, 0, 0}, ++ {0x33, 0, 0, 0, 0}, ++ {0x34, 0x88, 0x88, 0, 0}, ++ {0x35, 0x32, 0x32, 0, 0}, ++ {0x36, 0x77, 0x77, 0, 0}, ++ {0x37, 0x17, 0x17, 1, 1}, ++ {0x38, 0xf0, 0xf0, 1, 1}, ++ {0x39, 0x20, 0x20, 0, 0}, ++ {0x3A, 0x8, 0x8, 0, 0}, ++ {0x3B, 0x55, 0x55, 1, 1}, ++ {0x3C, 0, 0, 0, 0}, ++ {0x3D, 0x88, 0x88, 1, 1}, ++ {0x3E, 0, 0, 0, 0}, ++ {0x3F, 0x44, 0x44, 0, 0}, ++ {0x40, 0x7, 0x7, 1, 1}, ++ {0x41, 0x6, 0x6, 0, 0}, ++ {0x42, 0x4, 0x4, 0, 0}, ++ {0x43, 0, 0, 0, 0}, ++ {0x44, 0x8, 0x8, 0, 0}, ++ {0x45, 0x55, 0x55, 1, 1}, ++ {0x46, 0, 0, 0, 0}, ++ {0x47, 0x11, 0x11, 0, 0}, ++ {0x48, 0, 0, 0, 0}, ++ {0x49, 0x44, 0x44, 0, 0}, ++ {0x4A, 0x7, 0x7, 0, 0}, ++ {0x4B, 0x6, 0x6, 0, 0}, ++ {0x4C, 0x4, 0x4, 0, 0}, ++ {0x4D, 0, 0, 0, 0}, ++ {0x4E, 0, 0, 0, 0}, ++ {0x4F, 0x26, 0x26, 1, 1}, ++ {0x50, 0x26, 0x26, 1, 1}, ++ {0x51, 0xf, 0xf, 1, 1}, ++ {0x52, 0xf, 0xf, 1, 1}, ++ {0x53, 0x44, 0x44, 0, 0}, ++ {0x54, 0, 0, 0, 0}, ++ {0x55, 0, 0, 0, 0}, ++ {0x56, 0x8, 0x8, 0, 0}, ++ {0x57, 0x8, 0x8, 0, 0}, ++ {0x58, 0x7, 0x7, 0, 0}, ++ {0x59, 0x22, 0x22, 0, 0}, ++ {0x5A, 0x22, 0x22, 0, 0}, ++ {0x5B, 0x2, 0x2, 0, 0}, ++ {0x5C, 0x4, 0x4, 1, 1}, ++ {0x5D, 0x7, 0x7, 0, 0}, ++ {0x5E, 0x55, 0x55, 0, 0}, ++ {0x5F, 0x23, 0x23, 0, 0}, ++ {0x60, 0x41, 0x41, 0, 0}, ++ {0x61, 0x1, 0x1, 0, 0}, ++ {0x62, 0xa, 0xa, 0, 0}, ++ {0x63, 0, 0, 0, 0}, ++ {0x64, 0, 0, 0, 0}, ++ {0x65, 0, 0, 0, 0}, ++ {0x66, 0, 0, 0, 0}, ++ {0x67, 0, 0, 0, 0}, ++ {0x68, 0, 0, 0, 0}, ++ {0x69, 0, 0, 0, 0}, ++ {0x6A, 0, 0, 0, 0}, ++ {0x6B, 0xc, 0xc, 0, 0}, ++ {0x6C, 0, 0, 0, 0}, ++ {0x6D, 0, 0, 0, 0}, ++ {0x6E, 0, 0, 0, 0}, ++ {0x6F, 0, 0, 0, 0}, ++ {0x70, 0, 0, 0, 0}, ++ {0x71, 0, 0, 0, 0}, ++ {0x72, 0x22, 0x22, 0, 0}, ++ {0x73, 0x22, 0x22, 0, 0}, ++ {0x74, 0, 0, 1, 1}, ++ {0x75, 0xa, 0xa, 0, 0}, ++ {0x76, 0x1, 0x1, 0, 0}, ++ {0x77, 0x22, 0x22, 0, 0}, ++ {0x78, 0x30, 0x30, 0, 0}, ++ {0x79, 0, 0, 0, 0}, ++ {0x7A, 0, 0, 0, 0}, ++ {0x7B, 0, 0, 0, 0}, ++ {0x7C, 0, 0, 0, 0}, ++ {0x7D, 0x5, 0x5, 1, 1}, ++ {0x7E, 0, 0, 0, 0}, ++ {0x7F, 0, 0, 0, 0}, ++ {0x80, 0, 0, 0, 0}, ++ {0x81, 0, 0, 0, 0}, ++ {0x82, 0, 0, 0, 0}, ++ {0x83, 0, 0, 0, 0}, ++ {0x84, 0, 0, 0, 0}, ++ {0x85, 0, 0, 0, 0}, ++ {0x86, 0, 0, 0, 0}, ++ {0x87, 0, 0, 0, 0}, ++ {0x88, 0, 0, 0, 0}, ++ {0x89, 0, 0, 0, 0}, ++ {0x8A, 0, 0, 0, 0}, ++ {0x8B, 0, 0, 0, 0}, ++ {0x8C, 0, 0, 0, 0}, ++ {0x8D, 0, 0, 0, 0}, ++ {0x8E, 0, 0, 0, 0}, ++ {0x8F, 0, 0, 0, 0}, ++ {0x90, 0, 0, 0, 0}, ++ {0x91, 0, 0, 0, 0}, ++ {0x92, 0, 0, 0, 0}, ++ {0x93, 0, 0, 0, 0}, ++ {0x94, 0, 0, 0, 0}, ++ {0xFFFF, 0, 0, 0, 0}, ++}; ++ ++static struct radio_20xx_regs regs_2057_rev4[] = { ++ {0x00, 0x84, 0}, ++ {0x01, 0, 0}, ++ {0x02, 0x60, 0}, ++ {0x03, 0x1f, 0}, ++ {0x04, 0x4, 0}, ++ {0x05, 0x2, 0}, ++ {0x06, 0x1, 0}, ++ {0x07, 0x1, 0}, ++ {0x08, 0x1, 0}, ++ {0x09, 0x69, 0}, ++ {0x0A, 0x66, 0}, ++ {0x0B, 0x6, 0}, ++ {0x0C, 0x18, 0}, ++ {0x0D, 0x3, 0}, ++ {0x0E, 0x20, 1}, ++ {0x0F, 0x20, 0}, ++ {0x10, 0, 0}, ++ {0x11, 0x7c, 0}, ++ {0x12, 0x42, 0}, ++ {0x13, 0xbd, 0}, ++ {0x14, 0x7, 0}, ++ {0x15, 0xf7, 0}, ++ {0x16, 0x8, 0}, ++ {0x17, 0x17, 0}, ++ {0x18, 0x7, 0}, ++ {0x19, 0, 0}, ++ {0x1A, 0x2, 0}, ++ {0x1B, 0x13, 0}, ++ {0x1C, 0x3e, 0}, ++ {0x1D, 0x3e, 0}, ++ {0x1E, 0x96, 0}, ++ {0x1F, 0x4, 0}, ++ {0x20, 0, 0}, ++ {0x21, 0, 0}, ++ {0x22, 0x17, 0}, ++ {0x23, 0x4, 0}, ++ {0x24, 0x1, 0}, ++ {0x25, 0x6, 0}, ++ {0x26, 0x4, 0}, ++ {0x27, 0xd, 0}, ++ {0x28, 0xd, 0}, ++ {0x29, 0x30, 0}, ++ {0x2A, 0x32, 0}, ++ {0x2B, 0x8, 0}, ++ {0x2C, 0x1c, 0}, ++ {0x2D, 0x2, 0}, ++ {0x2E, 0x4, 0}, ++ {0x2F, 0x7f, 0}, ++ {0x30, 0x27, 0}, ++ {0x31, 0, 1}, ++ {0x32, 0, 1}, ++ {0x33, 0, 1}, ++ {0x34, 0, 0}, ++ {0x35, 0x26, 1}, ++ {0x36, 0x18, 0}, ++ {0x37, 0x7, 0}, ++ {0x38, 0x66, 0}, ++ {0x39, 0x66, 0}, ++ {0x3A, 0x66, 0}, ++ {0x3B, 0x66, 0}, ++ {0x3C, 0xff, 1}, ++ {0x3D, 0xff, 1}, ++ {0x3E, 0xff, 1}, ++ {0x3F, 0xff, 1}, ++ {0x40, 0x16, 0}, ++ {0x41, 0x7, 0}, ++ {0x42, 0x19, 0}, ++ {0x43, 0x7, 0}, ++ {0x44, 0x6, 0}, ++ {0x45, 0x3, 0}, ++ {0x46, 0x1, 0}, ++ {0x47, 0x7, 0}, ++ {0x48, 0x33, 0}, ++ {0x49, 0x5, 0}, ++ {0x4A, 0x77, 0}, ++ {0x4B, 0x66, 0}, ++ {0x4C, 0x66, 0}, ++ {0x4D, 0, 0}, ++ {0x4E, 0x4, 0}, ++ {0x4F, 0xc, 0}, ++ {0x50, 0, 0}, ++ {0x51, 0x75, 0}, ++ {0x56, 0x7, 0}, ++ {0x57, 0, 0}, ++ {0x58, 0, 0}, ++ {0x59, 0xa8, 0}, ++ {0x5A, 0, 0}, ++ {0x5B, 0x1f, 0}, ++ {0x5C, 0x30, 0}, ++ {0x5D, 0x1, 0}, ++ {0x5E, 0x30, 0}, ++ {0x5F, 0x70, 0}, ++ {0x60, 0, 0}, ++ {0x61, 0, 0}, ++ {0x62, 0x33, 1}, ++ {0x63, 0x19, 0}, ++ {0x64, 0x62, 0}, ++ {0x65, 0, 0}, ++ {0x66, 0x11, 0}, ++ {0x69, 0, 0}, ++ {0x6A, 0x7e, 0}, ++ {0x6B, 0x3f, 0}, ++ {0x6C, 0x7f, 0}, ++ {0x6D, 0x78, 0}, ++ {0x6E, 0xc8, 0}, ++ {0x6F, 0x88, 0}, ++ {0x70, 0x8, 0}, ++ {0x71, 0xf, 0}, ++ {0x72, 0xbc, 0}, ++ {0x73, 0x8, 0}, ++ {0x74, 0x60, 0}, ++ {0x75, 0x1e, 0}, ++ {0x76, 0x70, 0}, ++ {0x77, 0, 0}, ++ {0x78, 0, 0}, ++ {0x79, 0, 0}, ++ {0x7A, 0x33, 0}, ++ {0x7B, 0x1e, 0}, ++ {0x7C, 0x62, 0}, ++ {0x7D, 0x11, 0}, ++ {0x80, 0x3c, 0}, ++ {0x81, 0x9c, 0}, ++ {0x82, 0xa, 0}, ++ {0x83, 0x9d, 0}, ++ {0x84, 0xa, 0}, ++ {0x85, 0, 0}, ++ {0x86, 0x40, 0}, ++ {0x87, 0x40, 0}, ++ {0x88, 0x88, 0}, ++ {0x89, 0x10, 0}, ++ {0x8A, 0xf0, 1}, ++ {0x8B, 0x10, 1}, ++ {0x8C, 0xf0, 1}, ++ {0x8D, 0, 0}, ++ {0x8E, 0, 0}, ++ {0x8F, 0x10, 0}, ++ {0x90, 0x55, 0}, ++ {0x91, 0x3f, 1}, ++ {0x92, 0x36, 1}, ++ {0x93, 0, 0}, ++ {0x94, 0, 0}, ++ {0x95, 0, 0}, ++ {0x96, 0x87, 0}, ++ {0x97, 0x11, 0}, ++ {0x98, 0, 0}, ++ {0x99, 0x33, 0}, ++ {0x9A, 0x88, 0}, ++ {0x9B, 0, 0}, ++ {0x9C, 0x87, 0}, ++ {0x9D, 0x11, 0}, ++ {0x9E, 0, 0}, ++ {0x9F, 0x33, 0}, ++ {0xA0, 0x88, 0}, ++ {0xA1, 0xe1, 0}, ++ {0xA2, 0x3f, 0}, ++ {0xA3, 0x44, 0}, ++ {0xA4, 0x8c, 1}, ++ {0xA5, 0x6d, 0}, ++ {0xA6, 0x22, 0}, ++ {0xA7, 0xbe, 0}, ++ {0xA8, 0x55, 1}, ++ {0xA9, 0xc, 0}, ++ {0xAA, 0xc, 0}, ++ {0xAB, 0xaa, 0}, ++ {0xAC, 0x2, 0}, ++ {0xAD, 0, 0}, ++ {0xAE, 0x10, 0}, ++ {0xAF, 0x1, 1}, ++ {0xB0, 0, 0}, ++ {0xB1, 0, 0}, ++ {0xB2, 0x80, 0}, ++ {0xB3, 0x60, 0}, ++ {0xB4, 0x44, 0}, ++ {0xB5, 0x55, 0}, ++ {0xB6, 0x1, 0}, ++ {0xB7, 0x55, 0}, ++ {0xB8, 0x1, 0}, ++ {0xB9, 0x5, 0}, ++ {0xBA, 0x55, 0}, ++ {0xBB, 0x55, 0}, ++ {0xC1, 0, 0}, ++ {0xC2, 0, 0}, ++ {0xC3, 0, 0}, ++ {0xC4, 0, 0}, ++ {0xC5, 0, 0}, ++ {0xC6, 0, 0}, ++ {0xC7, 0, 0}, ++ {0xC8, 0, 0}, ++ {0xC9, 0, 0}, ++ {0xCA, 0, 0}, ++ {0xCB, 0, 0}, ++ {0xCC, 0, 0}, ++ {0xCD, 0, 0}, ++ {0xCE, 0x5e, 0}, ++ {0xCF, 0xc, 0}, ++ {0xD0, 0xc, 0}, ++ {0xD1, 0xc, 0}, ++ {0xD2, 0, 0}, ++ {0xD3, 0x2b, 0}, ++ {0xD4, 0xc, 0}, ++ {0xD5, 0, 0}, ++ {0xD6, 0x75, 0}, ++ {0xDB, 0x7, 0}, ++ {0xDC, 0, 0}, ++ {0xDD, 0, 0}, ++ {0xDE, 0xa8, 0}, ++ {0xDF, 0, 0}, ++ {0xE0, 0x1f, 0}, ++ {0xE1, 0x30, 0}, ++ {0xE2, 0x1, 0}, ++ {0xE3, 0x30, 0}, ++ {0xE4, 0x70, 0}, ++ {0xE5, 0, 0}, ++ {0xE6, 0, 0}, ++ {0xE7, 0x33, 0}, ++ {0xE8, 0x19, 0}, ++ {0xE9, 0x62, 0}, ++ {0xEA, 0, 0}, ++ {0xEB, 0x11, 0}, ++ {0xEE, 0, 0}, ++ {0xEF, 0x7e, 0}, ++ {0xF0, 0x3f, 0}, ++ {0xF1, 0x7f, 0}, ++ {0xF2, 0x78, 0}, ++ {0xF3, 0xc8, 0}, ++ {0xF4, 0x88, 0}, ++ {0xF5, 0x8, 0}, ++ {0xF6, 0xf, 0}, ++ {0xF7, 0xbc, 0}, ++ {0xF8, 0x8, 0}, ++ {0xF9, 0x60, 0}, ++ {0xFA, 0x1e, 0}, ++ {0xFB, 0x70, 0}, ++ {0xFC, 0, 0}, ++ {0xFD, 0, 0}, ++ {0xFE, 0, 0}, ++ {0xFF, 0x33, 0}, ++ {0x100, 0x1e, 0}, ++ {0x101, 0x62, 0}, ++ {0x102, 0x11, 0}, ++ {0x105, 0x3c, 0}, ++ {0x106, 0x9c, 0}, ++ {0x107, 0xa, 0}, ++ {0x108, 0x9d, 0}, ++ {0x109, 0xa, 0}, ++ {0x10A, 0, 0}, ++ {0x10B, 0x40, 0}, ++ {0x10C, 0x40, 0}, ++ {0x10D, 0x88, 0}, ++ {0x10E, 0x10, 0}, ++ {0x10F, 0xf0, 1}, ++ {0x110, 0x10, 1}, ++ {0x111, 0xf0, 1}, ++ {0x112, 0, 0}, ++ {0x113, 0, 0}, ++ {0x114, 0x10, 0}, ++ {0x115, 0x55, 0}, ++ {0x116, 0x3f, 1}, ++ {0x117, 0x36, 1}, ++ {0x118, 0, 0}, ++ {0x119, 0, 0}, ++ {0x11A, 0, 0}, ++ {0x11B, 0x87, 0}, ++ {0x11C, 0x11, 0}, ++ {0x11D, 0, 0}, ++ {0x11E, 0x33, 0}, ++ {0x11F, 0x88, 0}, ++ {0x120, 0, 0}, ++ {0x121, 0x87, 0}, ++ {0x122, 0x11, 0}, ++ {0x123, 0, 0}, ++ {0x124, 0x33, 0}, ++ {0x125, 0x88, 0}, ++ {0x126, 0xe1, 0}, ++ {0x127, 0x3f, 0}, ++ {0x128, 0x44, 0}, ++ {0x129, 0x8c, 1}, ++ {0x12A, 0x6d, 0}, ++ {0x12B, 0x22, 0}, ++ {0x12C, 0xbe, 0}, ++ {0x12D, 0x55, 1}, ++ {0x12E, 0xc, 0}, ++ {0x12F, 0xc, 0}, ++ {0x130, 0xaa, 0}, ++ {0x131, 0x2, 0}, ++ {0x132, 0, 0}, ++ {0x133, 0x10, 0}, ++ {0x134, 0x1, 1}, ++ {0x135, 0, 0}, ++ {0x136, 0, 0}, ++ {0x137, 0x80, 0}, ++ {0x138, 0x60, 0}, ++ {0x139, 0x44, 0}, ++ {0x13A, 0x55, 0}, ++ {0x13B, 0x1, 0}, ++ {0x13C, 0x55, 0}, ++ {0x13D, 0x1, 0}, ++ {0x13E, 0x5, 0}, ++ {0x13F, 0x55, 0}, ++ {0x140, 0x55, 0}, ++ {0x146, 0, 0}, ++ {0x147, 0, 0}, ++ {0x148, 0, 0}, ++ {0x149, 0, 0}, ++ {0x14A, 0, 0}, ++ {0x14B, 0, 0}, ++ {0x14C, 0, 0}, ++ {0x14D, 0, 0}, ++ {0x14E, 0, 0}, ++ {0x14F, 0, 0}, ++ {0x150, 0, 0}, ++ {0x151, 0, 0}, ++ {0x152, 0, 0}, ++ {0x153, 0, 0}, ++ {0x154, 0xc, 0}, ++ {0x155, 0xc, 0}, ++ {0x156, 0xc, 0}, ++ {0x157, 0, 0}, ++ {0x158, 0x2b, 0}, ++ {0x159, 0x84, 0}, ++ {0x15A, 0x15, 0}, ++ {0x15B, 0xf, 0}, ++ {0x15C, 0, 0}, ++ {0x15D, 0, 0}, ++ {0x15E, 0, 1}, ++ {0x15F, 0, 1}, ++ {0x160, 0, 1}, ++ {0x161, 0, 1}, ++ {0x162, 0, 1}, ++ {0x163, 0, 1}, ++ {0x164, 0, 0}, ++ {0x165, 0, 0}, ++ {0x166, 0, 0}, ++ {0x167, 0, 0}, ++ {0x168, 0, 0}, ++ {0x169, 0x2, 1}, ++ {0x16A, 0, 1}, ++ {0x16B, 0, 1}, ++ {0x16C, 0, 1}, ++ {0x16D, 0, 0}, ++ {0x170, 0, 0}, ++ {0x171, 0x77, 0}, ++ {0x172, 0x77, 0}, ++ {0x173, 0x77, 0}, ++ {0x174, 0x77, 0}, ++ {0x175, 0, 0}, ++ {0x176, 0x3, 0}, ++ {0x177, 0x37, 0}, ++ {0x178, 0x3, 0}, ++ {0x179, 0, 0}, ++ {0x17A, 0x21, 0}, ++ {0x17B, 0x21, 0}, ++ {0x17C, 0, 0}, ++ {0x17D, 0xaa, 0}, ++ {0x17E, 0, 0}, ++ {0x17F, 0xaa, 0}, ++ {0x180, 0, 0}, ++ {0x190, 0, 0}, ++ {0x191, 0x77, 0}, ++ {0x192, 0x77, 0}, ++ {0x193, 0x77, 0}, ++ {0x194, 0x77, 0}, ++ {0x195, 0, 0}, ++ {0x196, 0x3, 0}, ++ {0x197, 0x37, 0}, ++ {0x198, 0x3, 0}, ++ {0x199, 0, 0}, ++ {0x19A, 0x21, 0}, ++ {0x19B, 0x21, 0}, ++ {0x19C, 0, 0}, ++ {0x19D, 0xaa, 0}, ++ {0x19E, 0, 0}, ++ {0x19F, 0xaa, 0}, ++ {0x1A0, 0, 0}, ++ {0x1A1, 0x2, 0}, ++ {0x1A2, 0xf, 0}, ++ {0x1A3, 0xf, 0}, ++ {0x1A4, 0, 1}, ++ {0x1A5, 0, 1}, ++ {0x1A6, 0, 1}, ++ {0x1A7, 0x2, 0}, ++ {0x1A8, 0xf, 0}, ++ {0x1A9, 0xf, 0}, ++ {0x1AA, 0, 1}, ++ {0x1AB, 0, 1}, ++ {0x1AC, 0, 1}, ++ {0xFFFF, 0, 0}, ++}; ++ ++static struct radio_20xx_regs regs_2057_rev5[] = { ++ {0x00, 0, 1}, ++ {0x01, 0x57, 1}, ++ {0x02, 0x20, 1}, ++ {0x03, 0x1f, 0}, ++ {0x04, 0x4, 0}, ++ {0x05, 0x2, 0}, ++ {0x06, 0x1, 0}, ++ {0x07, 0x1, 0}, ++ {0x08, 0x1, 0}, ++ {0x09, 0x69, 0}, ++ {0x0A, 0x66, 0}, ++ {0x0B, 0x6, 0}, ++ {0x0C, 0x18, 0}, ++ {0x0D, 0x3, 0}, ++ {0x0E, 0x20, 0}, ++ {0x0F, 0x20, 0}, ++ {0x10, 0, 0}, ++ {0x11, 0x7c, 0}, ++ {0x12, 0x42, 0}, ++ {0x13, 0xbd, 0}, ++ {0x14, 0x7, 0}, ++ {0x15, 0x87, 0}, ++ {0x16, 0x8, 0}, ++ {0x17, 0x17, 0}, ++ {0x18, 0x7, 0}, ++ {0x19, 0, 0}, ++ {0x1A, 0x2, 0}, ++ {0x1B, 0x13, 0}, ++ {0x1C, 0x3e, 0}, ++ {0x1D, 0x3e, 0}, ++ {0x1E, 0x96, 0}, ++ {0x1F, 0x4, 0}, ++ {0x20, 0, 0}, ++ {0x21, 0, 0}, ++ {0x22, 0x17, 0}, ++ {0x23, 0x6, 1}, ++ {0x24, 0x1, 0}, ++ {0x25, 0x6, 0}, ++ {0x26, 0x4, 0}, ++ {0x27, 0xd, 0}, ++ {0x28, 0xd, 0}, ++ {0x29, 0x30, 0}, ++ {0x2A, 0x32, 0}, ++ {0x2B, 0x8, 0}, ++ {0x2C, 0x1c, 0}, ++ {0x2D, 0x2, 0}, ++ {0x2E, 0x4, 0}, ++ {0x2F, 0x7f, 0}, ++ {0x30, 0x27, 0}, ++ {0x31, 0, 1}, ++ {0x32, 0, 1}, ++ {0x33, 0, 1}, ++ {0x34, 0, 0}, ++ {0x35, 0x20, 0}, ++ {0x36, 0x18, 0}, ++ {0x37, 0x7, 0}, ++ {0x38, 0x66, 0}, ++ {0x39, 0x66, 0}, ++ {0x3C, 0xff, 0}, ++ {0x3D, 0xff, 0}, ++ {0x40, 0x16, 0}, ++ {0x41, 0x7, 0}, ++ {0x45, 0x3, 0}, ++ {0x46, 0x1, 0}, ++ {0x47, 0x7, 0}, ++ {0x4B, 0x66, 0}, ++ {0x4C, 0x66, 0}, ++ {0x4D, 0, 0}, ++ {0x4E, 0x4, 0}, ++ {0x4F, 0xc, 0}, ++ {0x50, 0, 0}, ++ {0x51, 0x70, 1}, ++ {0x56, 0x7, 0}, ++ {0x57, 0, 0}, ++ {0x58, 0, 0}, ++ {0x59, 0x88, 1}, ++ {0x5A, 0, 0}, ++ {0x5B, 0x1f, 0}, ++ {0x5C, 0x20, 1}, ++ {0x5D, 0x1, 0}, ++ {0x5E, 0x30, 0}, ++ {0x5F, 0x70, 0}, ++ {0x60, 0, 0}, ++ {0x61, 0, 0}, ++ {0x62, 0x33, 1}, ++ {0x63, 0xf, 1}, ++ {0x64, 0xf, 1}, ++ {0x65, 0, 0}, ++ {0x66, 0x11, 0}, ++ {0x80, 0x3c, 0}, ++ {0x81, 0x1, 1}, ++ {0x82, 0xa, 0}, ++ {0x85, 0, 0}, ++ {0x86, 0x40, 0}, ++ {0x87, 0x40, 0}, ++ {0x88, 0x88, 0}, ++ {0x89, 0x10, 0}, ++ {0x8A, 0xf0, 0}, ++ {0x8B, 0x10, 0}, ++ {0x8C, 0xf0, 0}, ++ {0x8F, 0x10, 0}, ++ {0x90, 0x55, 0}, ++ {0x91, 0x3f, 1}, ++ {0x92, 0x36, 1}, ++ {0x93, 0, 0}, ++ {0x94, 0, 0}, ++ {0x95, 0, 0}, ++ {0x96, 0x87, 0}, ++ {0x97, 0x11, 0}, ++ {0x98, 0, 0}, ++ {0x99, 0x33, 0}, ++ {0x9A, 0x88, 0}, ++ {0xA1, 0x20, 1}, ++ {0xA2, 0x3f, 0}, ++ {0xA3, 0x44, 0}, ++ {0xA4, 0x8c, 0}, ++ {0xA5, 0x6c, 0}, ++ {0xA6, 0x22, 0}, ++ {0xA7, 0xbe, 0}, ++ {0xA8, 0x55, 0}, ++ {0xAA, 0xc, 0}, ++ {0xAB, 0xaa, 0}, ++ {0xAC, 0x2, 0}, ++ {0xAD, 0, 0}, ++ {0xAE, 0x10, 0}, ++ {0xAF, 0x1, 0}, ++ {0xB0, 0, 0}, ++ {0xB1, 0, 0}, ++ {0xB2, 0x80, 0}, ++ {0xB3, 0x60, 0}, ++ {0xB4, 0x44, 0}, ++ {0xB5, 0x55, 0}, ++ {0xB6, 0x1, 0}, ++ {0xB7, 0x55, 0}, ++ {0xB8, 0x1, 0}, ++ {0xB9, 0x5, 0}, ++ {0xBA, 0x55, 0}, ++ {0xBB, 0x55, 0}, ++ {0xC3, 0, 0}, ++ {0xC4, 0, 0}, ++ {0xC5, 0, 0}, ++ {0xC6, 0, 0}, ++ {0xC7, 0, 0}, ++ {0xC8, 0, 0}, ++ {0xC9, 0, 0}, ++ {0xCA, 0, 0}, ++ {0xCB, 0, 0}, ++ {0xCD, 0, 0}, ++ {0xCE, 0x5e, 0}, ++ {0xCF, 0xc, 0}, ++ {0xD0, 0xc, 0}, ++ {0xD1, 0xc, 0}, ++ {0xD2, 0, 0}, ++ {0xD3, 0x2b, 0}, ++ {0xD4, 0xc, 0}, ++ {0xD5, 0, 0}, ++ {0xD6, 0x70, 1}, ++ {0xDB, 0x7, 0}, ++ {0xDC, 0, 0}, ++ {0xDD, 0, 0}, ++ {0xDE, 0x88, 1}, ++ {0xDF, 0, 0}, ++ {0xE0, 0x1f, 0}, ++ {0xE1, 0x20, 1}, ++ {0xE2, 0x1, 0}, ++ {0xE3, 0x30, 0}, ++ {0xE4, 0x70, 0}, ++ {0xE5, 0, 0}, ++ {0xE6, 0, 0}, ++ {0xE7, 0x33, 0}, ++ {0xE8, 0xf, 1}, ++ {0xE9, 0xf, 1}, ++ {0xEA, 0, 0}, ++ {0xEB, 0x11, 0}, ++ {0x105, 0x3c, 0}, ++ {0x106, 0x1, 1}, ++ {0x107, 0xa, 0}, ++ {0x10A, 0, 0}, ++ {0x10B, 0x40, 0}, ++ {0x10C, 0x40, 0}, ++ {0x10D, 0x88, 0}, ++ {0x10E, 0x10, 0}, ++ {0x10F, 0xf0, 0}, ++ {0x110, 0x10, 0}, ++ {0x111, 0xf0, 0}, ++ {0x114, 0x10, 0}, ++ {0x115, 0x55, 0}, ++ {0x116, 0x3f, 1}, ++ {0x117, 0x36, 1}, ++ {0x118, 0, 0}, ++ {0x119, 0, 0}, ++ {0x11A, 0, 0}, ++ {0x11B, 0x87, 0}, ++ {0x11C, 0x11, 0}, ++ {0x11D, 0, 0}, ++ {0x11E, 0x33, 0}, ++ {0x11F, 0x88, 0}, ++ {0x126, 0x20, 1}, ++ {0x127, 0x3f, 0}, ++ {0x128, 0x44, 0}, ++ {0x129, 0x8c, 0}, ++ {0x12A, 0x6c, 0}, ++ {0x12B, 0x22, 0}, ++ {0x12C, 0xbe, 0}, ++ {0x12D, 0x55, 0}, ++ {0x12F, 0xc, 0}, ++ {0x130, 0xaa, 0}, ++ {0x131, 0x2, 0}, ++ {0x132, 0, 0}, ++ {0x133, 0x10, 0}, ++ {0x134, 0x1, 0}, ++ {0x135, 0, 0}, ++ {0x136, 0, 0}, ++ {0x137, 0x80, 0}, ++ {0x138, 0x60, 0}, ++ {0x139, 0x44, 0}, ++ {0x13A, 0x55, 0}, ++ {0x13B, 0x1, 0}, ++ {0x13C, 0x55, 0}, ++ {0x13D, 0x1, 0}, ++ {0x13E, 0x5, 0}, ++ {0x13F, 0x55, 0}, ++ {0x140, 0x55, 0}, ++ {0x148, 0, 0}, ++ {0x149, 0, 0}, ++ {0x14A, 0, 0}, ++ {0x14B, 0, 0}, ++ {0x14C, 0, 0}, ++ {0x14D, 0, 0}, ++ {0x14E, 0, 0}, ++ {0x14F, 0, 0}, ++ {0x150, 0, 0}, ++ {0x154, 0xc, 0}, ++ {0x155, 0xc, 0}, ++ {0x156, 0xc, 0}, ++ {0x157, 0, 0}, ++ {0x158, 0x2b, 0}, ++ {0x159, 0x84, 0}, ++ {0x15A, 0x15, 0}, ++ {0x15B, 0xf, 0}, ++ {0x15C, 0, 0}, ++ {0x15D, 0, 0}, ++ {0x15E, 0, 1}, ++ {0x15F, 0, 1}, ++ {0x160, 0, 1}, ++ {0x161, 0, 1}, ++ {0x162, 0, 1}, ++ {0x163, 0, 1}, ++ {0x164, 0, 0}, ++ {0x165, 0, 0}, ++ {0x166, 0, 0}, ++ {0x167, 0, 0}, ++ {0x168, 0, 0}, ++ {0x169, 0, 0}, ++ {0x16A, 0, 1}, ++ {0x16B, 0, 1}, ++ {0x16C, 0, 1}, ++ {0x16D, 0, 0}, ++ {0x170, 0, 0}, ++ {0x171, 0x77, 0}, ++ {0x172, 0x77, 0}, ++ {0x173, 0x77, 0}, ++ {0x174, 0x77, 0}, ++ {0x175, 0, 0}, ++ {0x176, 0x3, 0}, ++ {0x177, 0x37, 0}, ++ {0x178, 0x3, 0}, ++ {0x179, 0, 0}, ++ {0x17B, 0x21, 0}, ++ {0x17C, 0, 0}, ++ {0x17D, 0xaa, 0}, ++ {0x17E, 0, 0}, ++ {0x190, 0, 0}, ++ {0x191, 0x77, 0}, ++ {0x192, 0x77, 0}, ++ {0x193, 0x77, 0}, ++ {0x194, 0x77, 0}, ++ {0x195, 0, 0}, ++ {0x196, 0x3, 0}, ++ {0x197, 0x37, 0}, ++ {0x198, 0x3, 0}, ++ {0x199, 0, 0}, ++ {0x19B, 0x21, 0}, ++ {0x19C, 0, 0}, ++ {0x19D, 0xaa, 0}, ++ {0x19E, 0, 0}, ++ {0x1A1, 0x2, 0}, ++ {0x1A2, 0xf, 0}, ++ {0x1A3, 0xf, 0}, ++ {0x1A4, 0, 1}, ++ {0x1A5, 0, 1}, ++ {0x1A6, 0, 1}, ++ {0x1A7, 0x2, 0}, ++ {0x1A8, 0xf, 0}, ++ {0x1A9, 0xf, 0}, ++ {0x1AA, 0, 1}, ++ {0x1AB, 0, 1}, ++ {0x1AC, 0, 1}, ++ {0x1AD, 0x84, 0}, ++ {0x1AE, 0x60, 0}, ++ {0x1AF, 0x47, 0}, ++ {0x1B0, 0x47, 0}, ++ {0x1B1, 0, 0}, ++ {0x1B2, 0, 0}, ++ {0x1B3, 0, 0}, ++ {0x1B4, 0, 0}, ++ {0x1B5, 0, 0}, ++ {0x1B6, 0, 0}, ++ {0x1B7, 0xc, 1}, ++ {0x1B8, 0, 0}, ++ {0x1B9, 0, 0}, ++ {0x1BA, 0, 0}, ++ {0x1BB, 0, 0}, ++ {0x1BC, 0, 0}, ++ {0x1BD, 0, 0}, ++ {0x1BE, 0, 0}, ++ {0x1BF, 0, 0}, ++ {0x1C0, 0, 0}, ++ {0x1C1, 0x1, 1}, ++ {0x1C2, 0x80, 1}, ++ {0x1C3, 0, 0}, ++ {0x1C4, 0, 0}, ++ {0x1C5, 0, 0}, ++ {0x1C6, 0, 0}, ++ {0x1C7, 0, 0}, ++ {0x1C8, 0, 0}, ++ {0x1C9, 0, 0}, ++ {0x1CA, 0, 0}, ++ {0xFFFF, 0, 0} ++}; ++ ++static struct radio_20xx_regs regs_2057_rev5v1[] = { ++ {0x00, 0x15, 1}, ++ {0x01, 0x57, 1}, ++ {0x02, 0x20, 1}, ++ {0x03, 0x1f, 0}, ++ {0x04, 0x4, 0}, ++ {0x05, 0x2, 0}, ++ {0x06, 0x1, 0}, ++ {0x07, 0x1, 0}, ++ {0x08, 0x1, 0}, ++ {0x09, 0x69, 0}, ++ {0x0A, 0x66, 0}, ++ {0x0B, 0x6, 0}, ++ {0x0C, 0x18, 0}, ++ {0x0D, 0x3, 0}, ++ {0x0E, 0x20, 0}, ++ {0x0F, 0x20, 0}, ++ {0x10, 0, 0}, ++ {0x11, 0x7c, 0}, ++ {0x12, 0x42, 0}, ++ {0x13, 0xbd, 0}, ++ {0x14, 0x7, 0}, ++ {0x15, 0x87, 0}, ++ {0x16, 0x8, 0}, ++ {0x17, 0x17, 0}, ++ {0x18, 0x7, 0}, ++ {0x19, 0, 0}, ++ {0x1A, 0x2, 0}, ++ {0x1B, 0x13, 0}, ++ {0x1C, 0x3e, 0}, ++ {0x1D, 0x3e, 0}, ++ {0x1E, 0x96, 0}, ++ {0x1F, 0x4, 0}, ++ {0x20, 0, 0}, ++ {0x21, 0, 0}, ++ {0x22, 0x17, 0}, ++ {0x23, 0x6, 1}, ++ {0x24, 0x1, 0}, ++ {0x25, 0x6, 0}, ++ {0x26, 0x4, 0}, ++ {0x27, 0xd, 0}, ++ {0x28, 0xd, 0}, ++ {0x29, 0x30, 0}, ++ {0x2A, 0x32, 0}, ++ {0x2B, 0x8, 0}, ++ {0x2C, 0x1c, 0}, ++ {0x2D, 0x2, 0}, ++ {0x2E, 0x4, 0}, ++ {0x2F, 0x7f, 0}, ++ {0x30, 0x27, 0}, ++ {0x31, 0, 1}, ++ {0x32, 0, 1}, ++ {0x33, 0, 1}, ++ {0x34, 0, 0}, ++ {0x35, 0x20, 0}, ++ {0x36, 0x18, 0}, ++ {0x37, 0x7, 0}, ++ {0x38, 0x66, 0}, ++ {0x39, 0x66, 0}, ++ {0x3C, 0xff, 0}, ++ {0x3D, 0xff, 0}, ++ {0x40, 0x16, 0}, ++ {0x41, 0x7, 0}, ++ {0x45, 0x3, 0}, ++ {0x46, 0x1, 0}, ++ {0x47, 0x7, 0}, ++ {0x4B, 0x66, 0}, ++ {0x4C, 0x66, 0}, ++ {0x4D, 0, 0}, ++ {0x4E, 0x4, 0}, ++ {0x4F, 0xc, 0}, ++ {0x50, 0, 0}, ++ {0x51, 0x70, 1}, ++ {0x56, 0x7, 0}, ++ {0x57, 0, 0}, ++ {0x58, 0, 0}, ++ {0x59, 0x88, 1}, ++ {0x5A, 0, 0}, ++ {0x5B, 0x1f, 0}, ++ {0x5C, 0x20, 1}, ++ {0x5D, 0x1, 0}, ++ {0x5E, 0x30, 0}, ++ {0x5F, 0x70, 0}, ++ {0x60, 0, 0}, ++ {0x61, 0, 0}, ++ {0x62, 0x33, 1}, ++ {0x63, 0xf, 1}, ++ {0x64, 0xf, 1}, ++ {0x65, 0, 0}, ++ {0x66, 0x11, 0}, ++ {0x80, 0x3c, 0}, ++ {0x81, 0x1, 1}, ++ {0x82, 0xa, 0}, ++ {0x85, 0, 0}, ++ {0x86, 0x40, 0}, ++ {0x87, 0x40, 0}, ++ {0x88, 0x88, 0}, ++ {0x89, 0x10, 0}, ++ {0x8A, 0xf0, 0}, ++ {0x8B, 0x10, 0}, ++ {0x8C, 0xf0, 0}, ++ {0x8F, 0x10, 0}, ++ {0x90, 0x55, 0}, ++ {0x91, 0x3f, 1}, ++ {0x92, 0x36, 1}, ++ {0x93, 0, 0}, ++ {0x94, 0, 0}, ++ {0x95, 0, 0}, ++ {0x96, 0x87, 0}, ++ {0x97, 0x11, 0}, ++ {0x98, 0, 0}, ++ {0x99, 0x33, 0}, ++ {0x9A, 0x88, 0}, ++ {0xA1, 0x20, 1}, ++ {0xA2, 0x3f, 0}, ++ {0xA3, 0x44, 0}, ++ {0xA4, 0x8c, 0}, ++ {0xA5, 0x6c, 0}, ++ {0xA6, 0x22, 0}, ++ {0xA7, 0xbe, 0}, ++ {0xA8, 0x55, 0}, ++ {0xAA, 0xc, 0}, ++ {0xAB, 0xaa, 0}, ++ {0xAC, 0x2, 0}, ++ {0xAD, 0, 0}, ++ {0xAE, 0x10, 0}, ++ {0xAF, 0x1, 0}, ++ {0xB0, 0, 0}, ++ {0xB1, 0, 0}, ++ {0xB2, 0x80, 0}, ++ {0xB3, 0x60, 0}, ++ {0xB4, 0x44, 0}, ++ {0xB5, 0x55, 0}, ++ {0xB6, 0x1, 0}, ++ {0xB7, 0x55, 0}, ++ {0xB8, 0x1, 0}, ++ {0xB9, 0x5, 0}, ++ {0xBA, 0x55, 0}, ++ {0xBB, 0x55, 0}, ++ {0xC3, 0, 0}, ++ {0xC4, 0, 0}, ++ {0xC5, 0, 0}, ++ {0xC6, 0, 0}, ++ {0xC7, 0, 0}, ++ {0xC8, 0, 0}, ++ {0xC9, 0x1, 1}, ++ {0xCA, 0, 0}, ++ {0xCB, 0, 0}, ++ {0xCD, 0, 0}, ++ {0xCE, 0x5e, 0}, ++ {0xCF, 0xc, 0}, ++ {0xD0, 0xc, 0}, ++ {0xD1, 0xc, 0}, ++ {0xD2, 0, 0}, ++ {0xD3, 0x2b, 0}, ++ {0xD4, 0xc, 0}, ++ {0xD5, 0, 0}, ++ {0xD6, 0x70, 1}, ++ {0xDB, 0x7, 0}, ++ {0xDC, 0, 0}, ++ {0xDD, 0, 0}, ++ {0xDE, 0x88, 1}, ++ {0xDF, 0, 0}, ++ {0xE0, 0x1f, 0}, ++ {0xE1, 0x20, 1}, ++ {0xE2, 0x1, 0}, ++ {0xE3, 0x30, 0}, ++ {0xE4, 0x70, 0}, ++ {0xE5, 0, 0}, ++ {0xE6, 0, 0}, ++ {0xE7, 0x33, 0}, ++ {0xE8, 0xf, 1}, ++ {0xE9, 0xf, 1}, ++ {0xEA, 0, 0}, ++ {0xEB, 0x11, 0}, ++ {0x105, 0x3c, 0}, ++ {0x106, 0x1, 1}, ++ {0x107, 0xa, 0}, ++ {0x10A, 0, 0}, ++ {0x10B, 0x40, 0}, ++ {0x10C, 0x40, 0}, ++ {0x10D, 0x88, 0}, ++ {0x10E, 0x10, 0}, ++ {0x10F, 0xf0, 0}, ++ {0x110, 0x10, 0}, ++ {0x111, 0xf0, 0}, ++ {0x114, 0x10, 0}, ++ {0x115, 0x55, 0}, ++ {0x116, 0x3f, 1}, ++ {0x117, 0x36, 1}, ++ {0x118, 0, 0}, ++ {0x119, 0, 0}, ++ {0x11A, 0, 0}, ++ {0x11B, 0x87, 0}, ++ {0x11C, 0x11, 0}, ++ {0x11D, 0, 0}, ++ {0x11E, 0x33, 0}, ++ {0x11F, 0x88, 0}, ++ {0x126, 0x20, 1}, ++ {0x127, 0x3f, 0}, ++ {0x128, 0x44, 0}, ++ {0x129, 0x8c, 0}, ++ {0x12A, 0x6c, 0}, ++ {0x12B, 0x22, 0}, ++ {0x12C, 0xbe, 0}, ++ {0x12D, 0x55, 0}, ++ {0x12F, 0xc, 0}, ++ {0x130, 0xaa, 0}, ++ {0x131, 0x2, 0}, ++ {0x132, 0, 0}, ++ {0x133, 0x10, 0}, ++ {0x134, 0x1, 0}, ++ {0x135, 0, 0}, ++ {0x136, 0, 0}, ++ {0x137, 0x80, 0}, ++ {0x138, 0x60, 0}, ++ {0x139, 0x44, 0}, ++ {0x13A, 0x55, 0}, ++ {0x13B, 0x1, 0}, ++ {0x13C, 0x55, 0}, ++ {0x13D, 0x1, 0}, ++ {0x13E, 0x5, 0}, ++ {0x13F, 0x55, 0}, ++ {0x140, 0x55, 0}, ++ {0x148, 0, 0}, ++ {0x149, 0, 0}, ++ {0x14A, 0, 0}, ++ {0x14B, 0, 0}, ++ {0x14C, 0, 0}, ++ {0x14D, 0, 0}, ++ {0x14E, 0x1, 1}, ++ {0x14F, 0, 0}, ++ {0x150, 0, 0}, ++ {0x154, 0xc, 0}, ++ {0x155, 0xc, 0}, ++ {0x156, 0xc, 0}, ++ {0x157, 0, 0}, ++ {0x158, 0x2b, 0}, ++ {0x159, 0x84, 0}, ++ {0x15A, 0x15, 0}, ++ {0x15B, 0xf, 0}, ++ {0x15C, 0, 0}, ++ {0x15D, 0, 0}, ++ {0x15E, 0, 1}, ++ {0x15F, 0, 1}, ++ {0x160, 0, 1}, ++ {0x161, 0, 1}, ++ {0x162, 0, 1}, ++ {0x163, 0, 1}, ++ {0x164, 0, 0}, ++ {0x165, 0, 0}, ++ {0x166, 0, 0}, ++ {0x167, 0, 0}, ++ {0x168, 0, 0}, ++ {0x169, 0, 0}, ++ {0x16A, 0, 1}, ++ {0x16B, 0, 1}, ++ {0x16C, 0, 1}, ++ {0x16D, 0, 0}, ++ {0x170, 0, 0}, ++ {0x171, 0x77, 0}, ++ {0x172, 0x77, 0}, ++ {0x173, 0x77, 0}, ++ {0x174, 0x77, 0}, ++ {0x175, 0, 0}, ++ {0x176, 0x3, 0}, ++ {0x177, 0x37, 0}, ++ {0x178, 0x3, 0}, ++ {0x179, 0, 0}, ++ {0x17B, 0x21, 0}, ++ {0x17C, 0, 0}, ++ {0x17D, 0xaa, 0}, ++ {0x17E, 0, 0}, ++ {0x190, 0, 0}, ++ {0x191, 0x77, 0}, ++ {0x192, 0x77, 0}, ++ {0x193, 0x77, 0}, ++ {0x194, 0x77, 0}, ++ {0x195, 0, 0}, ++ {0x196, 0x3, 0}, ++ {0x197, 0x37, 0}, ++ {0x198, 0x3, 0}, ++ {0x199, 0, 0}, ++ {0x19B, 0x21, 0}, ++ {0x19C, 0, 0}, ++ {0x19D, 0xaa, 0}, ++ {0x19E, 0, 0}, ++ {0x1A1, 0x2, 0}, ++ {0x1A2, 0xf, 0}, ++ {0x1A3, 0xf, 0}, ++ {0x1A4, 0, 1}, ++ {0x1A5, 0, 1}, ++ {0x1A6, 0, 1}, ++ {0x1A7, 0x2, 0}, ++ {0x1A8, 0xf, 0}, ++ {0x1A9, 0xf, 0}, ++ {0x1AA, 0, 1}, ++ {0x1AB, 0, 1}, ++ {0x1AC, 0, 1}, ++ {0x1AD, 0x84, 0}, ++ {0x1AE, 0x60, 0}, ++ {0x1AF, 0x47, 0}, ++ {0x1B0, 0x47, 0}, ++ {0x1B1, 0, 0}, ++ {0x1B2, 0, 0}, ++ {0x1B3, 0, 0}, ++ {0x1B4, 0, 0}, ++ {0x1B5, 0, 0}, ++ {0x1B6, 0, 0}, ++ {0x1B7, 0xc, 1}, ++ {0x1B8, 0, 0}, ++ {0x1B9, 0, 0}, ++ {0x1BA, 0, 0}, ++ {0x1BB, 0, 0}, ++ {0x1BC, 0, 0}, ++ {0x1BD, 0, 0}, ++ {0x1BE, 0, 0}, ++ {0x1BF, 0, 0}, ++ {0x1C0, 0, 0}, ++ {0x1C1, 0x1, 1}, ++ {0x1C2, 0x80, 1}, ++ {0x1C3, 0, 0}, ++ {0x1C4, 0, 0}, ++ {0x1C5, 0, 0}, ++ {0x1C6, 0, 0}, ++ {0x1C7, 0, 0}, ++ {0x1C8, 0, 0}, ++ {0x1C9, 0, 0}, ++ {0x1CA, 0, 0}, ++ {0xFFFF, 0, 0} ++}; ++ ++static struct radio_20xx_regs regs_2057_rev7[] = { ++ {0x00, 0, 1}, ++ {0x01, 0x57, 1}, ++ {0x02, 0x20, 1}, ++ {0x03, 0x1f, 0}, ++ {0x04, 0x4, 0}, ++ {0x05, 0x2, 0}, ++ {0x06, 0x1, 0}, ++ {0x07, 0x1, 0}, ++ {0x08, 0x1, 0}, ++ {0x09, 0x69, 0}, ++ {0x0A, 0x66, 0}, ++ {0x0B, 0x6, 0}, ++ {0x0C, 0x18, 0}, ++ {0x0D, 0x3, 0}, ++ {0x0E, 0x20, 0}, ++ {0x0F, 0x20, 0}, ++ {0x10, 0, 0}, ++ {0x11, 0x7c, 0}, ++ {0x12, 0x42, 0}, ++ {0x13, 0xbd, 0}, ++ {0x14, 0x7, 0}, ++ {0x15, 0x87, 0}, ++ {0x16, 0x8, 0}, ++ {0x17, 0x17, 0}, ++ {0x18, 0x7, 0}, ++ {0x19, 0, 0}, ++ {0x1A, 0x2, 0}, ++ {0x1B, 0x13, 0}, ++ {0x1C, 0x3e, 0}, ++ {0x1D, 0x3e, 0}, ++ {0x1E, 0x96, 0}, ++ {0x1F, 0x4, 0}, ++ {0x20, 0, 0}, ++ {0x21, 0, 0}, ++ {0x22, 0x17, 0}, ++ {0x23, 0x6, 0}, ++ {0x24, 0x1, 0}, ++ {0x25, 0x6, 0}, ++ {0x26, 0x4, 0}, ++ {0x27, 0xd, 0}, ++ {0x28, 0xd, 0}, ++ {0x29, 0x30, 0}, ++ {0x2A, 0x32, 0}, ++ {0x2B, 0x8, 0}, ++ {0x2C, 0x1c, 0}, ++ {0x2D, 0x2, 0}, ++ {0x2E, 0x4, 0}, ++ {0x2F, 0x7f, 0}, ++ {0x30, 0x27, 0}, ++ {0x31, 0, 1}, ++ {0x32, 0, 1}, ++ {0x33, 0, 1}, ++ {0x34, 0, 0}, ++ {0x35, 0x20, 0}, ++ {0x36, 0x18, 0}, ++ {0x37, 0x7, 0}, ++ {0x38, 0x66, 0}, ++ {0x39, 0x66, 0}, ++ {0x3A, 0x66, 0}, ++ {0x3B, 0x66, 0}, ++ {0x3C, 0xff, 0}, ++ {0x3D, 0xff, 0}, ++ {0x3E, 0xff, 0}, ++ {0x3F, 0xff, 0}, ++ {0x40, 0x16, 0}, ++ {0x41, 0x7, 0}, ++ {0x42, 0x19, 0}, ++ {0x43, 0x7, 0}, ++ {0x44, 0x6, 0}, ++ {0x45, 0x3, 0}, ++ {0x46, 0x1, 0}, ++ {0x47, 0x7, 0}, ++ {0x48, 0x33, 0}, ++ {0x49, 0x5, 0}, ++ {0x4A, 0x77, 0}, ++ {0x4B, 0x66, 0}, ++ {0x4C, 0x66, 0}, ++ {0x4D, 0, 0}, ++ {0x4E, 0x4, 0}, ++ {0x4F, 0xc, 0}, ++ {0x50, 0, 0}, ++ {0x51, 0x70, 1}, ++ {0x56, 0x7, 0}, ++ {0x57, 0, 0}, ++ {0x58, 0, 0}, ++ {0x59, 0x88, 1}, ++ {0x5A, 0, 0}, ++ {0x5B, 0x1f, 0}, ++ {0x5C, 0x20, 1}, ++ {0x5D, 0x1, 0}, ++ {0x5E, 0x30, 0}, ++ {0x5F, 0x70, 0}, ++ {0x60, 0, 0}, ++ {0x61, 0, 0}, ++ {0x62, 0x33, 1}, ++ {0x63, 0xf, 1}, ++ {0x64, 0x13, 1}, ++ {0x65, 0, 0}, ++ {0x66, 0xee, 1}, ++ {0x69, 0, 0}, ++ {0x6A, 0x7e, 0}, ++ {0x6B, 0x3f, 0}, ++ {0x6C, 0x7f, 0}, ++ {0x6D, 0x78, 0}, ++ {0x6E, 0x58, 1}, ++ {0x6F, 0x88, 0}, ++ {0x70, 0x8, 0}, ++ {0x71, 0xf, 0}, ++ {0x72, 0xbc, 0}, ++ {0x73, 0x8, 0}, ++ {0x74, 0x60, 0}, ++ {0x75, 0x13, 1}, ++ {0x76, 0x70, 0}, ++ {0x77, 0, 0}, ++ {0x78, 0, 0}, ++ {0x79, 0, 0}, ++ {0x7A, 0x33, 0}, ++ {0x7B, 0x13, 1}, ++ {0x7C, 0x14, 1}, ++ {0x7D, 0xee, 1}, ++ {0x80, 0x3c, 0}, ++ {0x81, 0x1, 1}, ++ {0x82, 0xa, 0}, ++ {0x83, 0x9d, 0}, ++ {0x84, 0xa, 0}, ++ {0x85, 0, 0}, ++ {0x86, 0x40, 0}, ++ {0x87, 0x40, 0}, ++ {0x88, 0x88, 0}, ++ {0x89, 0x10, 0}, ++ {0x8A, 0xf0, 0}, ++ {0x8B, 0x10, 0}, ++ {0x8C, 0xf0, 0}, ++ {0x8D, 0, 0}, ++ {0x8E, 0, 0}, ++ {0x8F, 0x10, 0}, ++ {0x90, 0x55, 0}, ++ {0x91, 0x3f, 1}, ++ {0x92, 0x36, 1}, ++ {0x93, 0, 0}, ++ {0x94, 0, 0}, ++ {0x95, 0, 0}, ++ {0x96, 0x87, 0}, ++ {0x97, 0x11, 0}, ++ {0x98, 0, 0}, ++ {0x99, 0x33, 0}, ++ {0x9A, 0x88, 0}, ++ {0x9B, 0, 0}, ++ {0x9C, 0x87, 0}, ++ {0x9D, 0x11, 0}, ++ {0x9E, 0, 0}, ++ {0x9F, 0x33, 0}, ++ {0xA0, 0x88, 0}, ++ {0xA1, 0x20, 1}, ++ {0xA2, 0x3f, 0}, ++ {0xA3, 0x44, 0}, ++ {0xA4, 0x8c, 0}, ++ {0xA5, 0x6c, 0}, ++ {0xA6, 0x22, 0}, ++ {0xA7, 0xbe, 0}, ++ {0xA8, 0x55, 0}, ++ {0xAA, 0xc, 0}, ++ {0xAB, 0xaa, 0}, ++ {0xAC, 0x2, 0}, ++ {0xAD, 0, 0}, ++ {0xAE, 0x10, 0}, ++ {0xAF, 0x1, 0}, ++ {0xB0, 0, 0}, ++ {0xB1, 0, 0}, ++ {0xB2, 0x80, 0}, ++ {0xB3, 0x60, 0}, ++ {0xB4, 0x44, 0}, ++ {0xB5, 0x55, 0}, ++ {0xB6, 0x1, 0}, ++ {0xB7, 0x55, 0}, ++ {0xB8, 0x1, 0}, ++ {0xB9, 0x5, 0}, ++ {0xBA, 0x55, 0}, ++ {0xBB, 0x55, 0}, ++ {0xC1, 0, 0}, ++ {0xC2, 0, 0}, ++ {0xC3, 0, 0}, ++ {0xC4, 0, 0}, ++ {0xC5, 0, 0}, ++ {0xC6, 0, 0}, ++ {0xC7, 0, 0}, ++ {0xC8, 0, 0}, ++ {0xC9, 0, 0}, ++ {0xCA, 0, 0}, ++ {0xCB, 0, 0}, ++ {0xCC, 0, 0}, ++ {0xCD, 0, 0}, ++ {0xCE, 0x5e, 0}, ++ {0xCF, 0xc, 0}, ++ {0xD0, 0xc, 0}, ++ {0xD1, 0xc, 0}, ++ {0xD2, 0, 0}, ++ {0xD3, 0x2b, 0}, ++ {0xD4, 0xc, 0}, ++ {0xD5, 0, 0}, ++ {0xD6, 0x70, 1}, ++ {0xDB, 0x7, 0}, ++ {0xDC, 0, 0}, ++ {0xDD, 0, 0}, ++ {0xDE, 0x88, 1}, ++ {0xDF, 0, 0}, ++ {0xE0, 0x1f, 0}, ++ {0xE1, 0x20, 1}, ++ {0xE2, 0x1, 0}, ++ {0xE3, 0x30, 0}, ++ {0xE4, 0x70, 0}, ++ {0xE5, 0, 0}, ++ {0xE6, 0, 0}, ++ {0xE7, 0x33, 0}, ++ {0xE8, 0xf, 1}, ++ {0xE9, 0x13, 1}, ++ {0xEA, 0, 0}, ++ {0xEB, 0xee, 1}, ++ {0xEE, 0, 0}, ++ {0xEF, 0x7e, 0}, ++ {0xF0, 0x3f, 0}, ++ {0xF1, 0x7f, 0}, ++ {0xF2, 0x78, 0}, ++ {0xF3, 0x58, 1}, ++ {0xF4, 0x88, 0}, ++ {0xF5, 0x8, 0}, ++ {0xF6, 0xf, 0}, ++ {0xF7, 0xbc, 0}, ++ {0xF8, 0x8, 0}, ++ {0xF9, 0x60, 0}, ++ {0xFA, 0x13, 1}, ++ {0xFB, 0x70, 0}, ++ {0xFC, 0, 0}, ++ {0xFD, 0, 0}, ++ {0xFE, 0, 0}, ++ {0xFF, 0x33, 0}, ++ {0x100, 0x13, 1}, ++ {0x101, 0x14, 1}, ++ {0x102, 0xee, 1}, ++ {0x105, 0x3c, 0}, ++ {0x106, 0x1, 1}, ++ {0x107, 0xa, 0}, ++ {0x108, 0x9d, 0}, ++ {0x109, 0xa, 0}, ++ {0x10A, 0, 0}, ++ {0x10B, 0x40, 0}, ++ {0x10C, 0x40, 0}, ++ {0x10D, 0x88, 0}, ++ {0x10E, 0x10, 0}, ++ {0x10F, 0xf0, 0}, ++ {0x110, 0x10, 0}, ++ {0x111, 0xf0, 0}, ++ {0x112, 0, 0}, ++ {0x113, 0, 0}, ++ {0x114, 0x10, 0}, ++ {0x115, 0x55, 0}, ++ {0x116, 0x3f, 1}, ++ {0x117, 0x36, 1}, ++ {0x118, 0, 0}, ++ {0x119, 0, 0}, ++ {0x11A, 0, 0}, ++ {0x11B, 0x87, 0}, ++ {0x11C, 0x11, 0}, ++ {0x11D, 0, 0}, ++ {0x11E, 0x33, 0}, ++ {0x11F, 0x88, 0}, ++ {0x120, 0, 0}, ++ {0x121, 0x87, 0}, ++ {0x122, 0x11, 0}, ++ {0x123, 0, 0}, ++ {0x124, 0x33, 0}, ++ {0x125, 0x88, 0}, ++ {0x126, 0x20, 1}, ++ {0x127, 0x3f, 0}, ++ {0x128, 0x44, 0}, ++ {0x129, 0x8c, 0}, ++ {0x12A, 0x6c, 0}, ++ {0x12B, 0x22, 0}, ++ {0x12C, 0xbe, 0}, ++ {0x12D, 0x55, 0}, ++ {0x12F, 0xc, 0}, ++ {0x130, 0xaa, 0}, ++ {0x131, 0x2, 0}, ++ {0x132, 0, 0}, ++ {0x133, 0x10, 0}, ++ {0x134, 0x1, 0}, ++ {0x135, 0, 0}, ++ {0x136, 0, 0}, ++ {0x137, 0x80, 0}, ++ {0x138, 0x60, 0}, ++ {0x139, 0x44, 0}, ++ {0x13A, 0x55, 0}, ++ {0x13B, 0x1, 0}, ++ {0x13C, 0x55, 0}, ++ {0x13D, 0x1, 0}, ++ {0x13E, 0x5, 0}, ++ {0x13F, 0x55, 0}, ++ {0x140, 0x55, 0}, ++ {0x146, 0, 0}, ++ {0x147, 0, 0}, ++ {0x148, 0, 0}, ++ {0x149, 0, 0}, ++ {0x14A, 0, 0}, ++ {0x14B, 0, 0}, ++ {0x14C, 0, 0}, ++ {0x14D, 0, 0}, ++ {0x14E, 0, 0}, ++ {0x14F, 0, 0}, ++ {0x150, 0, 0}, ++ {0x151, 0, 0}, ++ {0x154, 0xc, 0}, ++ {0x155, 0xc, 0}, ++ {0x156, 0xc, 0}, ++ {0x157, 0, 0}, ++ {0x158, 0x2b, 0}, ++ {0x159, 0x84, 0}, ++ {0x15A, 0x15, 0}, ++ {0x15B, 0xf, 0}, ++ {0x15C, 0, 0}, ++ {0x15D, 0, 0}, ++ {0x15E, 0, 1}, ++ {0x15F, 0, 1}, ++ {0x160, 0, 1}, ++ {0x161, 0, 1}, ++ {0x162, 0, 1}, ++ {0x163, 0, 1}, ++ {0x164, 0, 0}, ++ {0x165, 0, 0}, ++ {0x166, 0, 0}, ++ {0x167, 0, 0}, ++ {0x168, 0, 0}, ++ {0x169, 0, 0}, ++ {0x16A, 0, 1}, ++ {0x16B, 0, 1}, ++ {0x16C, 0, 1}, ++ {0x16D, 0, 0}, ++ {0x170, 0, 0}, ++ {0x171, 0x77, 0}, ++ {0x172, 0x77, 0}, ++ {0x173, 0x77, 0}, ++ {0x174, 0x77, 0}, ++ {0x175, 0, 0}, ++ {0x176, 0x3, 0}, ++ {0x177, 0x37, 0}, ++ {0x178, 0x3, 0}, ++ {0x179, 0, 0}, ++ {0x17A, 0x21, 0}, ++ {0x17B, 0x21, 0}, ++ {0x17C, 0, 0}, ++ {0x17D, 0xaa, 0}, ++ {0x17E, 0, 0}, ++ {0x17F, 0xaa, 0}, ++ {0x180, 0, 0}, ++ {0x190, 0, 0}, ++ {0x191, 0x77, 0}, ++ {0x192, 0x77, 0}, ++ {0x193, 0x77, 0}, ++ {0x194, 0x77, 0}, ++ {0x195, 0, 0}, ++ {0x196, 0x3, 0}, ++ {0x197, 0x37, 0}, ++ {0x198, 0x3, 0}, ++ {0x199, 0, 0}, ++ {0x19A, 0x21, 0}, ++ {0x19B, 0x21, 0}, ++ {0x19C, 0, 0}, ++ {0x19D, 0xaa, 0}, ++ {0x19E, 0, 0}, ++ {0x19F, 0xaa, 0}, ++ {0x1A0, 0, 0}, ++ {0x1A1, 0x2, 0}, ++ {0x1A2, 0xf, 0}, ++ {0x1A3, 0xf, 0}, ++ {0x1A4, 0, 1}, ++ {0x1A5, 0, 1}, ++ {0x1A6, 0, 1}, ++ {0x1A7, 0x2, 0}, ++ {0x1A8, 0xf, 0}, ++ {0x1A9, 0xf, 0}, ++ {0x1AA, 0, 1}, ++ {0x1AB, 0, 1}, ++ {0x1AC, 0, 1}, ++ {0x1AD, 0x84, 0}, ++ {0x1AE, 0x60, 0}, ++ {0x1AF, 0x47, 0}, ++ {0x1B0, 0x47, 0}, ++ {0x1B1, 0, 0}, ++ {0x1B2, 0, 0}, ++ {0x1B3, 0, 0}, ++ {0x1B4, 0, 0}, ++ {0x1B5, 0, 0}, ++ {0x1B6, 0, 0}, ++ {0x1B7, 0x5, 1}, ++ {0x1B8, 0, 0}, ++ {0x1B9, 0, 0}, ++ {0x1BA, 0, 0}, ++ {0x1BB, 0, 0}, ++ {0x1BC, 0, 0}, ++ {0x1BD, 0, 0}, ++ {0x1BE, 0, 0}, ++ {0x1BF, 0, 0}, ++ {0x1C0, 0, 0}, ++ {0x1C1, 0, 0}, ++ {0x1C2, 0xa0, 1}, ++ {0x1C3, 0, 0}, ++ {0x1C4, 0, 0}, ++ {0x1C5, 0, 0}, ++ {0x1C6, 0, 0}, ++ {0x1C7, 0, 0}, ++ {0x1C8, 0, 0}, ++ {0x1C9, 0, 0}, ++ {0x1CA, 0, 0}, ++ {0xFFFF, 0, 0} ++}; ++ ++static struct radio_20xx_regs regs_2057_rev8[] = { ++ {0x00, 0x8, 1}, ++ {0x01, 0x57, 1}, ++ {0x02, 0x20, 1}, ++ {0x03, 0x1f, 0}, ++ {0x04, 0x4, 0}, ++ {0x05, 0x2, 0}, ++ {0x06, 0x1, 0}, ++ {0x07, 0x1, 0}, ++ {0x08, 0x1, 0}, ++ {0x09, 0x69, 0}, ++ {0x0A, 0x66, 0}, ++ {0x0B, 0x6, 0}, ++ {0x0C, 0x18, 0}, ++ {0x0D, 0x3, 0}, ++ {0x0E, 0x20, 0}, ++ {0x0F, 0x20, 0}, ++ {0x10, 0, 0}, ++ {0x11, 0x7c, 0}, ++ {0x12, 0x42, 0}, ++ {0x13, 0xbd, 0}, ++ {0x14, 0x7, 0}, ++ {0x15, 0x87, 0}, ++ {0x16, 0x8, 0}, ++ {0x17, 0x17, 0}, ++ {0x18, 0x7, 0}, ++ {0x19, 0, 0}, ++ {0x1A, 0x2, 0}, ++ {0x1B, 0x13, 0}, ++ {0x1C, 0x3e, 0}, ++ {0x1D, 0x3e, 0}, ++ {0x1E, 0x96, 0}, ++ {0x1F, 0x4, 0}, ++ {0x20, 0, 0}, ++ {0x21, 0, 0}, ++ {0x22, 0x17, 0}, ++ {0x23, 0x6, 0}, ++ {0x24, 0x1, 0}, ++ {0x25, 0x6, 0}, ++ {0x26, 0x4, 0}, ++ {0x27, 0xd, 0}, ++ {0x28, 0xd, 0}, ++ {0x29, 0x30, 0}, ++ {0x2A, 0x32, 0}, ++ {0x2B, 0x8, 0}, ++ {0x2C, 0x1c, 0}, ++ {0x2D, 0x2, 0}, ++ {0x2E, 0x4, 0}, ++ {0x2F, 0x7f, 0}, ++ {0x30, 0x27, 0}, ++ {0x31, 0, 1}, ++ {0x32, 0, 1}, ++ {0x33, 0, 1}, ++ {0x34, 0, 0}, ++ {0x35, 0x20, 0}, ++ {0x36, 0x18, 0}, ++ {0x37, 0x7, 0}, ++ {0x38, 0x66, 0}, ++ {0x39, 0x66, 0}, ++ {0x3A, 0x66, 0}, ++ {0x3B, 0x66, 0}, ++ {0x3C, 0xff, 0}, ++ {0x3D, 0xff, 0}, ++ {0x3E, 0xff, 0}, ++ {0x3F, 0xff, 0}, ++ {0x40, 0x16, 0}, ++ {0x41, 0x7, 0}, ++ {0x42, 0x19, 0}, ++ {0x43, 0x7, 0}, ++ {0x44, 0x6, 0}, ++ {0x45, 0x3, 0}, ++ {0x46, 0x1, 0}, ++ {0x47, 0x7, 0}, ++ {0x48, 0x33, 0}, ++ {0x49, 0x5, 0}, ++ {0x4A, 0x77, 0}, ++ {0x4B, 0x66, 0}, ++ {0x4C, 0x66, 0}, ++ {0x4D, 0, 0}, ++ {0x4E, 0x4, 0}, ++ {0x4F, 0xc, 0}, ++ {0x50, 0, 0}, ++ {0x51, 0x70, 1}, ++ {0x56, 0x7, 0}, ++ {0x57, 0, 0}, ++ {0x58, 0, 0}, ++ {0x59, 0x88, 1}, ++ {0x5A, 0, 0}, ++ {0x5B, 0x1f, 0}, ++ {0x5C, 0x20, 1}, ++ {0x5D, 0x1, 0}, ++ {0x5E, 0x30, 0}, ++ {0x5F, 0x70, 0}, ++ {0x60, 0, 0}, ++ {0x61, 0, 0}, ++ {0x62, 0x33, 1}, ++ {0x63, 0xf, 1}, ++ {0x64, 0xf, 1}, ++ {0x65, 0, 0}, ++ {0x66, 0x11, 0}, ++ {0x69, 0, 0}, ++ {0x6A, 0x7e, 0}, ++ {0x6B, 0x3f, 0}, ++ {0x6C, 0x7f, 0}, ++ {0x6D, 0x78, 0}, ++ {0x6E, 0x58, 1}, ++ {0x6F, 0x88, 0}, ++ {0x70, 0x8, 0}, ++ {0x71, 0xf, 0}, ++ {0x72, 0xbc, 0}, ++ {0x73, 0x8, 0}, ++ {0x74, 0x60, 0}, ++ {0x75, 0x13, 1}, ++ {0x76, 0x70, 0}, ++ {0x77, 0, 0}, ++ {0x78, 0, 0}, ++ {0x79, 0, 0}, ++ {0x7A, 0x33, 0}, ++ {0x7B, 0x13, 1}, ++ {0x7C, 0xf, 1}, ++ {0x7D, 0xee, 1}, ++ {0x80, 0x3c, 0}, ++ {0x81, 0x1, 1}, ++ {0x82, 0xa, 0}, ++ {0x83, 0x9d, 0}, ++ {0x84, 0xa, 0}, ++ {0x85, 0, 0}, ++ {0x86, 0x40, 0}, ++ {0x87, 0x40, 0}, ++ {0x88, 0x88, 0}, ++ {0x89, 0x10, 0}, ++ {0x8A, 0xf0, 0}, ++ {0x8B, 0x10, 0}, ++ {0x8C, 0xf0, 0}, ++ {0x8D, 0, 0}, ++ {0x8E, 0, 0}, ++ {0x8F, 0x10, 0}, ++ {0x90, 0x55, 0}, ++ {0x91, 0x3f, 1}, ++ {0x92, 0x36, 1}, ++ {0x93, 0, 0}, ++ {0x94, 0, 0}, ++ {0x95, 0, 0}, ++ {0x96, 0x87, 0}, ++ {0x97, 0x11, 0}, ++ {0x98, 0, 0}, ++ {0x99, 0x33, 0}, ++ {0x9A, 0x88, 0}, ++ {0x9B, 0, 0}, ++ {0x9C, 0x87, 0}, ++ {0x9D, 0x11, 0}, ++ {0x9E, 0, 0}, ++ {0x9F, 0x33, 0}, ++ {0xA0, 0x88, 0}, ++ {0xA1, 0x20, 1}, ++ {0xA2, 0x3f, 0}, ++ {0xA3, 0x44, 0}, ++ {0xA4, 0x8c, 0}, ++ {0xA5, 0x6c, 0}, ++ {0xA6, 0x22, 0}, ++ {0xA7, 0xbe, 0}, ++ {0xA8, 0x55, 0}, ++ {0xAA, 0xc, 0}, ++ {0xAB, 0xaa, 0}, ++ {0xAC, 0x2, 0}, ++ {0xAD, 0, 0}, ++ {0xAE, 0x10, 0}, ++ {0xAF, 0x1, 0}, ++ {0xB0, 0, 0}, ++ {0xB1, 0, 0}, ++ {0xB2, 0x80, 0}, ++ {0xB3, 0x60, 0}, ++ {0xB4, 0x44, 0}, ++ {0xB5, 0x55, 0}, ++ {0xB6, 0x1, 0}, ++ {0xB7, 0x55, 0}, ++ {0xB8, 0x1, 0}, ++ {0xB9, 0x5, 0}, ++ {0xBA, 0x55, 0}, ++ {0xBB, 0x55, 0}, ++ {0xC1, 0, 0}, ++ {0xC2, 0, 0}, ++ {0xC3, 0, 0}, ++ {0xC4, 0, 0}, ++ {0xC5, 0, 0}, ++ {0xC6, 0, 0}, ++ {0xC7, 0, 0}, ++ {0xC8, 0, 0}, ++ {0xC9, 0x1, 1}, ++ {0xCA, 0, 0}, ++ {0xCB, 0, 0}, ++ {0xCC, 0, 0}, ++ {0xCD, 0, 0}, ++ {0xCE, 0x5e, 0}, ++ {0xCF, 0xc, 0}, ++ {0xD0, 0xc, 0}, ++ {0xD1, 0xc, 0}, ++ {0xD2, 0, 0}, ++ {0xD3, 0x2b, 0}, ++ {0xD4, 0xc, 0}, ++ {0xD5, 0, 0}, ++ {0xD6, 0x70, 1}, ++ {0xDB, 0x7, 0}, ++ {0xDC, 0, 0}, ++ {0xDD, 0, 0}, ++ {0xDE, 0x88, 1}, ++ {0xDF, 0, 0}, ++ {0xE0, 0x1f, 0}, ++ {0xE1, 0x20, 1}, ++ {0xE2, 0x1, 0}, ++ {0xE3, 0x30, 0}, ++ {0xE4, 0x70, 0}, ++ {0xE5, 0, 0}, ++ {0xE6, 0, 0}, ++ {0xE7, 0x33, 0}, ++ {0xE8, 0xf, 1}, ++ {0xE9, 0xf, 1}, ++ {0xEA, 0, 0}, ++ {0xEB, 0x11, 0}, ++ {0xEE, 0, 0}, ++ {0xEF, 0x7e, 0}, ++ {0xF0, 0x3f, 0}, ++ {0xF1, 0x7f, 0}, ++ {0xF2, 0x78, 0}, ++ {0xF3, 0x58, 1}, ++ {0xF4, 0x88, 0}, ++ {0xF5, 0x8, 0}, ++ {0xF6, 0xf, 0}, ++ {0xF7, 0xbc, 0}, ++ {0xF8, 0x8, 0}, ++ {0xF9, 0x60, 0}, ++ {0xFA, 0x13, 1}, ++ {0xFB, 0x70, 0}, ++ {0xFC, 0, 0}, ++ {0xFD, 0, 0}, ++ {0xFE, 0, 0}, ++ {0xFF, 0x33, 0}, ++ {0x100, 0x13, 1}, ++ {0x101, 0xf, 1}, ++ {0x102, 0xee, 1}, ++ {0x105, 0x3c, 0}, ++ {0x106, 0x1, 1}, ++ {0x107, 0xa, 0}, ++ {0x108, 0x9d, 0}, ++ {0x109, 0xa, 0}, ++ {0x10A, 0, 0}, ++ {0x10B, 0x40, 0}, ++ {0x10C, 0x40, 0}, ++ {0x10D, 0x88, 0}, ++ {0x10E, 0x10, 0}, ++ {0x10F, 0xf0, 0}, ++ {0x110, 0x10, 0}, ++ {0x111, 0xf0, 0}, ++ {0x112, 0, 0}, ++ {0x113, 0, 0}, ++ {0x114, 0x10, 0}, ++ {0x115, 0x55, 0}, ++ {0x116, 0x3f, 1}, ++ {0x117, 0x36, 1}, ++ {0x118, 0, 0}, ++ {0x119, 0, 0}, ++ {0x11A, 0, 0}, ++ {0x11B, 0x87, 0}, ++ {0x11C, 0x11, 0}, ++ {0x11D, 0, 0}, ++ {0x11E, 0x33, 0}, ++ {0x11F, 0x88, 0}, ++ {0x120, 0, 0}, ++ {0x121, 0x87, 0}, ++ {0x122, 0x11, 0}, ++ {0x123, 0, 0}, ++ {0x124, 0x33, 0}, ++ {0x125, 0x88, 0}, ++ {0x126, 0x20, 1}, ++ {0x127, 0x3f, 0}, ++ {0x128, 0x44, 0}, ++ {0x129, 0x8c, 0}, ++ {0x12A, 0x6c, 0}, ++ {0x12B, 0x22, 0}, ++ {0x12C, 0xbe, 0}, ++ {0x12D, 0x55, 0}, ++ {0x12F, 0xc, 0}, ++ {0x130, 0xaa, 0}, ++ {0x131, 0x2, 0}, ++ {0x132, 0, 0}, ++ {0x133, 0x10, 0}, ++ {0x134, 0x1, 0}, ++ {0x135, 0, 0}, ++ {0x136, 0, 0}, ++ {0x137, 0x80, 0}, ++ {0x138, 0x60, 0}, ++ {0x139, 0x44, 0}, ++ {0x13A, 0x55, 0}, ++ {0x13B, 0x1, 0}, ++ {0x13C, 0x55, 0}, ++ {0x13D, 0x1, 0}, ++ {0x13E, 0x5, 0}, ++ {0x13F, 0x55, 0}, ++ {0x140, 0x55, 0}, ++ {0x146, 0, 0}, ++ {0x147, 0, 0}, ++ {0x148, 0, 0}, ++ {0x149, 0, 0}, ++ {0x14A, 0, 0}, ++ {0x14B, 0, 0}, ++ {0x14C, 0, 0}, ++ {0x14D, 0, 0}, ++ {0x14E, 0x1, 1}, ++ {0x14F, 0, 0}, ++ {0x150, 0, 0}, ++ {0x151, 0, 0}, ++ {0x154, 0xc, 0}, ++ {0x155, 0xc, 0}, ++ {0x156, 0xc, 0}, ++ {0x157, 0, 0}, ++ {0x158, 0x2b, 0}, ++ {0x159, 0x84, 0}, ++ {0x15A, 0x15, 0}, ++ {0x15B, 0xf, 0}, ++ {0x15C, 0, 0}, ++ {0x15D, 0, 0}, ++ {0x15E, 0, 1}, ++ {0x15F, 0, 1}, ++ {0x160, 0, 1}, ++ {0x161, 0, 1}, ++ {0x162, 0, 1}, ++ {0x163, 0, 1}, ++ {0x164, 0, 0}, ++ {0x165, 0, 0}, ++ {0x166, 0, 0}, ++ {0x167, 0, 0}, ++ {0x168, 0, 0}, ++ {0x169, 0, 0}, ++ {0x16A, 0, 1}, ++ {0x16B, 0, 1}, ++ {0x16C, 0, 1}, ++ {0x16D, 0, 0}, ++ {0x170, 0, 0}, ++ {0x171, 0x77, 0}, ++ {0x172, 0x77, 0}, ++ {0x173, 0x77, 0}, ++ {0x174, 0x77, 0}, ++ {0x175, 0, 0}, ++ {0x176, 0x3, 0}, ++ {0x177, 0x37, 0}, ++ {0x178, 0x3, 0}, ++ {0x179, 0, 0}, ++ {0x17A, 0x21, 0}, ++ {0x17B, 0x21, 0}, ++ {0x17C, 0, 0}, ++ {0x17D, 0xaa, 0}, ++ {0x17E, 0, 0}, ++ {0x17F, 0xaa, 0}, ++ {0x180, 0, 0}, ++ {0x190, 0, 0}, ++ {0x191, 0x77, 0}, ++ {0x192, 0x77, 0}, ++ {0x193, 0x77, 0}, ++ {0x194, 0x77, 0}, ++ {0x195, 0, 0}, ++ {0x196, 0x3, 0}, ++ {0x197, 0x37, 0}, ++ {0x198, 0x3, 0}, ++ {0x199, 0, 0}, ++ {0x19A, 0x21, 0}, ++ {0x19B, 0x21, 0}, ++ {0x19C, 0, 0}, ++ {0x19D, 0xaa, 0}, ++ {0x19E, 0, 0}, ++ {0x19F, 0xaa, 0}, ++ {0x1A0, 0, 0}, ++ {0x1A1, 0x2, 0}, ++ {0x1A2, 0xf, 0}, ++ {0x1A3, 0xf, 0}, ++ {0x1A4, 0, 1}, ++ {0x1A5, 0, 1}, ++ {0x1A6, 0, 1}, ++ {0x1A7, 0x2, 0}, ++ {0x1A8, 0xf, 0}, ++ {0x1A9, 0xf, 0}, ++ {0x1AA, 0, 1}, ++ {0x1AB, 0, 1}, ++ {0x1AC, 0, 1}, ++ {0x1AD, 0x84, 0}, ++ {0x1AE, 0x60, 0}, ++ {0x1AF, 0x47, 0}, ++ {0x1B0, 0x47, 0}, ++ {0x1B1, 0, 0}, ++ {0x1B2, 0, 0}, ++ {0x1B3, 0, 0}, ++ {0x1B4, 0, 0}, ++ {0x1B5, 0, 0}, ++ {0x1B6, 0, 0}, ++ {0x1B7, 0x5, 1}, ++ {0x1B8, 0, 0}, ++ {0x1B9, 0, 0}, ++ {0x1BA, 0, 0}, ++ {0x1BB, 0, 0}, ++ {0x1BC, 0, 0}, ++ {0x1BD, 0, 0}, ++ {0x1BE, 0, 0}, ++ {0x1BF, 0, 0}, ++ {0x1C0, 0, 0}, ++ {0x1C1, 0, 0}, ++ {0x1C2, 0xa0, 1}, ++ {0x1C3, 0, 0}, ++ {0x1C4, 0, 0}, ++ {0x1C5, 0, 0}, ++ {0x1C6, 0, 0}, ++ {0x1C7, 0, 0}, ++ {0x1C8, 0, 0}, ++ {0x1C9, 0, 0}, ++ {0x1CA, 0, 0}, ++ {0xFFFF, 0, 0} ++}; ++ ++static s16 nphy_def_lnagains[] = { -2, 10, 19, 25 }; ++ ++static s32 nphy_lnagain_est0[] = { -315, 40370 }; ++static s32 nphy_lnagain_est1[] = { -224, 23242 }; ++ ++static const u16 tbl_iqcal_gainparams_nphy[2][NPHY_IQCAL_NUMGAINS][8] = { ++ { ++ {0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69}, ++ {0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69}, ++ {0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68}, ++ {0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67}, ++ {0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66}, ++ {0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65}, ++ {0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65}, ++ {0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65}, ++ {0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65} ++ }, ++ { ++ {0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79}, ++ {0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79}, ++ {0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79}, ++ {0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78}, ++ {0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78}, ++ {0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78}, ++ {0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78}, ++ {0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78}, ++ {0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78} ++ } ++}; ++ ++static const u32 nphy_tpc_txgain[] = { ++ 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, ++ 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, ++ 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844, ++ 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44, ++ 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844, ++ 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644, ++ 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444, ++ 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44, ++ 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844, ++ 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44, ++ 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944, ++ 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744, ++ 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544, ++ 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44, ++ 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844, ++ 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44, ++ 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944, ++ 0x03902942, 0x03902844, 0x03902842, 0x03902744, ++ 0x03902742, 0x03902644, 0x03902642, 0x03902544, ++ 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44, ++ 0x03802a42, 0x03802944, 0x03802942, 0x03802844, ++ 0x03802842, 0x03802744, 0x03802742, 0x03802644, ++ 0x03802642, 0x03802544, 0x03802542, 0x03802444, ++ 0x03802442, 0x03802344, 0x03802342, 0x03802244, ++ 0x03802242, 0x03802144, 0x03802142, 0x03802044, ++ 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44, ++ 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44, ++ 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44, ++ 0x03801a42, 0x03801944, 0x03801942, 0x03801844, ++ 0x03801842, 0x03801744, 0x03801742, 0x03801644, ++ 0x03801642, 0x03801544, 0x03801542, 0x03801444, ++ 0x03801442, 0x03801344, 0x03801342, 0x00002b00 ++}; ++ ++static const u16 nphy_tpc_loscale[] = { ++ 256, 256, 271, 271, 287, 256, 256, 271, ++ 271, 287, 287, 304, 304, 256, 256, 271, ++ 271, 287, 287, 304, 304, 322, 322, 341, ++ 341, 362, 362, 383, 383, 256, 256, 271, ++ 271, 287, 287, 304, 304, 322, 322, 256, ++ 256, 271, 271, 287, 287, 304, 304, 322, ++ 322, 341, 341, 362, 362, 256, 256, 271, ++ 271, 287, 287, 304, 304, 322, 322, 256, ++ 256, 271, 271, 287, 287, 304, 304, 322, ++ 322, 341, 341, 362, 362, 256, 256, 271, ++ 271, 287, 287, 304, 304, 322, 322, 341, ++ 341, 362, 362, 383, 383, 406, 406, 430, ++ 430, 455, 455, 482, 482, 511, 511, 541, ++ 541, 573, 573, 607, 607, 643, 643, 681, ++ 681, 722, 722, 764, 764, 810, 810, 858, ++ 858, 908, 908, 962, 962, 1019, 1019, 256 ++}; ++ ++static u32 nphy_tpc_txgain_ipa[] = { ++ 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, ++ 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, ++ 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, ++ 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025, ++ 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029, ++ 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025, ++ 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029, ++ 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025, ++ 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029, ++ 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025, ++ 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029, ++ 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025, ++ 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029, ++ 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025, ++ 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029, ++ 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025, ++ 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029, ++ 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025, ++ 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029, ++ 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025, ++ 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029, ++ 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025, ++ 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029, ++ 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025, ++ 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029, ++ 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025, ++ 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029, ++ 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025, ++ 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029, ++ 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025, ++ 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029, ++ 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_rev5[] = { ++ 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, ++ 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, ++ 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, ++ 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025, ++ 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029, ++ 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025, ++ 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029, ++ 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025, ++ 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029, ++ 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025, ++ 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029, ++ 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025, ++ 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029, ++ 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025, ++ 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029, ++ 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025, ++ 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029, ++ 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025, ++ 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029, ++ 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025, ++ 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029, ++ 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025, ++ 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029, ++ 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025, ++ 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029, ++ 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025, ++ 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029, ++ 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025, ++ 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029, ++ 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025, ++ 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029, ++ 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_rev6[] = { ++ 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, ++ 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, ++ 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, ++ 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025, ++ 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029, ++ 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025, ++ 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029, ++ 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025, ++ 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029, ++ 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025, ++ 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029, ++ 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025, ++ 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029, ++ 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025, ++ 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029, ++ 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025, ++ 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029, ++ 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025, ++ 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029, ++ 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025, ++ 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029, ++ 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025, ++ 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029, ++ 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025, ++ 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029, ++ 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025, ++ 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029, ++ 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025, ++ 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029, ++ 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025, ++ 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029, ++ 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_2g_2057rev3[] = { ++ 0x70ff0040, 0x70f7003e, 0x70ef003b, 0x70e70039, ++ 0x70df0037, 0x70d70036, 0x70cf0033, 0x70c70032, ++ 0x70bf0031, 0x70b7002f, 0x70af002e, 0x70a7002d, ++ 0x709f002d, 0x7097002c, 0x708f002c, 0x7087002c, ++ 0x707f002b, 0x7077002c, 0x706f002c, 0x7067002d, ++ 0x705f002e, 0x705f002b, 0x705f0029, 0x7057002a, ++ 0x70570028, 0x704f002a, 0x7047002c, 0x7047002a, ++ 0x70470028, 0x70470026, 0x70470024, 0x70470022, ++ 0x7047001f, 0x70370027, 0x70370024, 0x70370022, ++ 0x70370020, 0x7037001f, 0x7037001d, 0x7037001b, ++ 0x7037001a, 0x70370018, 0x70370017, 0x7027001e, ++ 0x7027001d, 0x7027001a, 0x701f0024, 0x701f0022, ++ 0x701f0020, 0x701f001f, 0x701f001d, 0x701f001b, ++ 0x701f001a, 0x701f0018, 0x701f0017, 0x701f0015, ++ 0x701f0014, 0x701f0013, 0x701f0012, 0x701f0011, ++ 0x70170019, 0x70170018, 0x70170016, 0x70170015, ++ 0x70170014, 0x70170013, 0x70170012, 0x70170010, ++ 0x70170010, 0x7017000f, 0x700f001d, 0x700f001b, ++ 0x700f001a, 0x700f0018, 0x700f0017, 0x700f0015, ++ 0x700f0015, 0x700f0013, 0x700f0013, 0x700f0011, ++ 0x700f0010, 0x700f0010, 0x700f000f, 0x700f000e, ++ 0x700f000d, 0x700f000c, 0x700f000b, 0x700f000b, ++ 0x700f000b, 0x700f000a, 0x700f0009, 0x700f0009, ++ 0x700f0009, 0x700f0008, 0x700f0007, 0x700f0007, ++ 0x700f0006, 0x700f0006, 0x700f0006, 0x700f0006, ++ 0x700f0005, 0x700f0005, 0x700f0005, 0x700f0004, ++ 0x700f0004, 0x700f0004, 0x700f0004, 0x700f0004, ++ 0x700f0004, 0x700f0003, 0x700f0003, 0x700f0003, ++ 0x700f0003, 0x700f0002, 0x700f0002, 0x700f0002, ++ 0x700f0002, 0x700f0002, 0x700f0002, 0x700f0001, ++ 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001, ++ 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_2g_2057rev4n6[] = { ++ 0xf0ff0040, 0xf0f7003e, 0xf0ef003b, 0xf0e70039, ++ 0xf0df0037, 0xf0d70036, 0xf0cf0033, 0xf0c70032, ++ 0xf0bf0031, 0xf0b7002f, 0xf0af002e, 0xf0a7002d, ++ 0xf09f002d, 0xf097002c, 0xf08f002c, 0xf087002c, ++ 0xf07f002b, 0xf077002c, 0xf06f002c, 0xf067002d, ++ 0xf05f002e, 0xf05f002b, 0xf05f0029, 0xf057002a, ++ 0xf0570028, 0xf04f002a, 0xf047002c, 0xf047002a, ++ 0xf0470028, 0xf0470026, 0xf0470024, 0xf0470022, ++ 0xf047001f, 0xf0370027, 0xf0370024, 0xf0370022, ++ 0xf0370020, 0xf037001f, 0xf037001d, 0xf037001b, ++ 0xf037001a, 0xf0370018, 0xf0370017, 0xf027001e, ++ 0xf027001d, 0xf027001a, 0xf01f0024, 0xf01f0022, ++ 0xf01f0020, 0xf01f001f, 0xf01f001d, 0xf01f001b, ++ 0xf01f001a, 0xf01f0018, 0xf01f0017, 0xf01f0015, ++ 0xf01f0014, 0xf01f0013, 0xf01f0012, 0xf01f0011, ++ 0xf0170019, 0xf0170018, 0xf0170016, 0xf0170015, ++ 0xf0170014, 0xf0170013, 0xf0170012, 0xf0170010, ++ 0xf0170010, 0xf017000f, 0xf00f001d, 0xf00f001b, ++ 0xf00f001a, 0xf00f0018, 0xf00f0017, 0xf00f0015, ++ 0xf00f0015, 0xf00f0013, 0xf00f0013, 0xf00f0011, ++ 0xf00f0010, 0xf00f0010, 0xf00f000f, 0xf00f000e, ++ 0xf00f000d, 0xf00f000c, 0xf00f000b, 0xf00f000b, ++ 0xf00f000b, 0xf00f000a, 0xf00f0009, 0xf00f0009, ++ 0xf00f0009, 0xf00f0008, 0xf00f0007, 0xf00f0007, ++ 0xf00f0006, 0xf00f0006, 0xf00f0006, 0xf00f0006, ++ 0xf00f0005, 0xf00f0005, 0xf00f0005, 0xf00f0004, ++ 0xf00f0004, 0xf00f0004, 0xf00f0004, 0xf00f0004, ++ 0xf00f0004, 0xf00f0003, 0xf00f0003, 0xf00f0003, ++ 0xf00f0003, 0xf00f0002, 0xf00f0002, 0xf00f0002, ++ 0xf00f0002, 0xf00f0002, 0xf00f0002, 0xf00f0001, ++ 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001, ++ 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_2g_2057rev5[] = { ++ 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e, ++ 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033, ++ 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e, ++ 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d, ++ 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c, ++ 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d, ++ 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a, ++ 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029, ++ 0x30270027, 0x30270025, 0x30270023, 0x301f002c, ++ 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024, ++ 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b, ++ 0x30170028, 0x30170026, 0x30170024, 0x30170022, ++ 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b, ++ 0x3017001a, 0x30170018, 0x30170017, 0x30170015, ++ 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024, ++ 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d, ++ 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017, ++ 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215, ++ 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_2g_2057rev7[] = { ++ 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e, ++ 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033, ++ 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e, ++ 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d, ++ 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c, ++ 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d, ++ 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a, ++ 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029, ++ 0x30270027, 0x30270025, 0x30270023, 0x301f002c, ++ 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024, ++ 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b, ++ 0x30170028, 0x30170026, 0x30170024, 0x30170022, ++ 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b, ++ 0x3017001a, 0x30170018, 0x30170017, 0x30170015, ++ 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024, ++ 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d, ++ 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017, ++ 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215, ++ 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, ++ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_5g[] = { ++ 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, ++ 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, ++ 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, ++ 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022, ++ 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025, ++ 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027, ++ 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023, ++ 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027, ++ 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022, ++ 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025, ++ 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021, ++ 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026, ++ 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022, ++ 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026, ++ 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022, ++ 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026, ++ 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022, ++ 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026, ++ 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022, ++ 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026, ++ 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021, ++ 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026, ++ 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029, ++ 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024, ++ 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027, ++ 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023, ++ 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026, ++ 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022, ++ 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025, ++ 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027, ++ 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022, ++ 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f ++}; ++ ++static u32 nphy_tpc_txgain_ipa_5g_2057[] = { ++ 0x7f7f0044, 0x7f7f0040, 0x7f7f003c, 0x7f7f0039, ++ 0x7f7f0036, 0x7e7f003c, 0x7e7f0038, 0x7e7f0035, ++ 0x7d7f003c, 0x7d7f0039, 0x7d7f0036, 0x7d7f0033, ++ 0x7c7f003b, 0x7c7f0037, 0x7c7f0034, 0x7b7f003a, ++ 0x7b7f0036, 0x7b7f0033, 0x7a7f003c, 0x7a7f0039, ++ 0x7a7f0036, 0x7a7f0033, 0x797f003b, 0x797f0038, ++ 0x797f0035, 0x797f0032, 0x787f003b, 0x787f0038, ++ 0x787f0035, 0x787f0032, 0x777f003a, 0x777f0037, ++ 0x777f0034, 0x777f0031, 0x767f003a, 0x767f0036, ++ 0x767f0033, 0x767f0031, 0x757f003a, 0x757f0037, ++ 0x757f0034, 0x747f003c, 0x747f0039, 0x747f0036, ++ 0x747f0033, 0x737f003b, 0x737f0038, 0x737f0035, ++ 0x737f0032, 0x727f0039, 0x727f0036, 0x727f0033, ++ 0x727f0030, 0x717f003a, 0x717f0037, 0x717f0034, ++ 0x707f003b, 0x707f0038, 0x707f0035, 0x707f0032, ++ 0x707f002f, 0x707f002d, 0x707f002a, 0x707f0028, ++ 0x707f0025, 0x707f0023, 0x707f0021, 0x707f0020, ++ 0x707f001e, 0x707f001c, 0x707f001b, 0x707f0019, ++ 0x707f0018, 0x707f0016, 0x707f0015, 0x707f0014, ++ 0x707f0013, 0x707f0012, 0x707f0011, 0x707f0010, ++ 0x707f000f, 0x707f000e, 0x707f000d, 0x707f000d, ++ 0x707f000c, 0x707f000b, 0x707f000b, 0x707f000a, ++ 0x707f0009, 0x707f0009, 0x707f0008, 0x707f0008, ++ 0x707f0007, 0x707f0007, 0x707f0007, 0x707f0006, ++ 0x707f0006, 0x707f0006, 0x707f0005, 0x707f0005, ++ 0x707f0005, 0x707f0004, 0x707f0004, 0x707f0004, ++ 0x707f0004, 0x707f0004, 0x707f0003, 0x707f0003, ++ 0x707f0003, 0x707f0003, 0x707f0003, 0x707f0003, ++ 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, ++ 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, ++ 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001, ++ 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001 ++}; ++ ++static u32 nphy_tpc_txgain_ipa_5g_2057rev7[] = { ++ 0x6f7f0031, 0x6f7f002e, 0x6f7f002c, 0x6f7f002a, ++ 0x6f7f0027, 0x6e7f002e, 0x6e7f002c, 0x6e7f002a, ++ 0x6d7f0030, 0x6d7f002d, 0x6d7f002a, 0x6d7f0028, ++ 0x6c7f0030, 0x6c7f002d, 0x6c7f002b, 0x6b7f002e, ++ 0x6b7f002c, 0x6b7f002a, 0x6b7f0027, 0x6a7f002e, ++ 0x6a7f002c, 0x6a7f002a, 0x697f0030, 0x697f002e, ++ 0x697f002b, 0x697f0029, 0x687f002f, 0x687f002d, ++ 0x687f002a, 0x687f0027, 0x677f002f, 0x677f002d, ++ 0x677f002a, 0x667f0031, 0x667f002e, 0x667f002c, ++ 0x667f002a, 0x657f0030, 0x657f002e, 0x657f002b, ++ 0x657f0029, 0x647f0030, 0x647f002d, 0x647f002b, ++ 0x647f0029, 0x637f002f, 0x637f002d, 0x637f002a, ++ 0x627f0030, 0x627f002d, 0x627f002b, 0x627f0029, ++ 0x617f0030, 0x617f002e, 0x617f002b, 0x617f0029, ++ 0x607f002f, 0x607f002d, 0x607f002a, 0x607f0027, ++ 0x607f0026, 0x607f0023, 0x607f0021, 0x607f0020, ++ 0x607f001e, 0x607f001c, 0x607f001a, 0x607f0019, ++ 0x607f0018, 0x607f0016, 0x607f0015, 0x607f0014, ++ 0x607f0012, 0x607f0012, 0x607f0011, 0x607f000f, ++ 0x607f000f, 0x607f000e, 0x607f000d, 0x607f000c, ++ 0x607f000c, 0x607f000b, 0x607f000b, 0x607f000a, ++ 0x607f0009, 0x607f0009, 0x607f0008, 0x607f0008, ++ 0x607f0008, 0x607f0007, 0x607f0007, 0x607f0006, ++ 0x607f0006, 0x607f0005, 0x607f0005, 0x607f0005, ++ 0x607f0005, 0x607f0005, 0x607f0004, 0x607f0004, ++ 0x607f0004, 0x607f0004, 0x607f0003, 0x607f0003, ++ 0x607f0003, 0x607f0003, 0x607f0002, 0x607f0002, ++ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, ++ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, ++ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, ++ 0x607f0002, 0x607f0001, 0x607f0001, 0x607f0001, ++ 0x607f0001, 0x607f0001, 0x607f0001, 0x607f0001 ++}; ++ ++static s8 nphy_papd_pga_gain_delta_ipa_2g[] = { ++ -114, -108, -98, -91, -84, -78, -70, -62, ++ -54, -46, -39, -31, -23, -15, -8, 0 ++}; ++ ++static s8 nphy_papd_pga_gain_delta_ipa_5g[] = { ++ -100, -95, -89, -83, -77, -70, -63, -56, ++ -48, -41, -33, -25, -19, -12, -6, 0 ++}; ++ ++static s16 nphy_papd_padgain_dlt_2g_2057rev3n4[] = { ++ -159, -113, -86, -72, -62, -54, -48, -43, ++ -39, -35, -31, -28, -25, -23, -20, -18, ++ -17, -15, -13, -11, -10, -8, -7, -6, ++ -5, -4, -3, -3, -2, -1, -1, 0 ++}; ++ ++static s16 nphy_papd_padgain_dlt_2g_2057rev5[] = { ++ -109, -109, -82, -68, -58, -50, -44, -39, ++ -35, -31, -28, -26, -23, -21, -19, -17, ++ -16, -14, -13, -11, -10, -9, -8, -7, ++ -5, -5, -4, -3, -2, -1, -1, 0 ++}; ++ ++static s16 nphy_papd_padgain_dlt_2g_2057rev7[] = { ++ -122, -122, -95, -80, -69, -61, -54, -49, ++ -43, -39, -35, -32, -28, -26, -23, -21, ++ -18, -16, -15, -13, -11, -10, -8, -7, ++ -6, -5, -4, -3, -2, -1, -1, 0 ++}; ++ ++static s8 nphy_papd_pgagain_dlt_5g_2057[] = { ++ -107, -101, -92, -85, -78, -71, -62, -55, ++ -47, -39, -32, -24, -19, -12, -6, 0 ++}; ++ ++static s8 nphy_papd_pgagain_dlt_5g_2057rev7[] = { ++ -110, -104, -95, -88, -81, -74, -66, -58, ++ -50, -44, -36, -28, -23, -15, -8, 0 ++}; ++ ++static u8 pad_gain_codes_used_2057rev5[] = { ++ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, ++ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ++}; ++ ++static u8 pad_gain_codes_used_2057rev7[] = { ++ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, ++ 5, 4, 3, 2, 1 ++}; ++ ++static u8 pad_all_gain_codes_2057[] = { ++ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, ++ 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, ++ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, ++ 1, 0 ++}; ++ ++static u8 pga_all_gain_codes_2057[] = { ++ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ++}; ++ ++static u32 nphy_papd_scaltbl[] = { ++ 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038, ++ 0x0887003c, 0x081f003f, 0x07a20043, 0x07340047, ++ 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059, ++ 0x0571005e, 0x051e0064, 0x04d3006a, 0x04910070, ++ 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d, ++ 0x036f0095, 0x033d009e, 0x030b00a8, 0x02e000b2, ++ 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0, ++ 0x022900ed, 0x020a00fb, 0x01ec010a, 0x01d0011a, ++ 0x01b7012a, 0x019e013c, 0x0187014f, 0x01720162, ++ 0x015d0177, 0x0149018e, 0x013701a5, 0x012601be, ++ 0x011501d9, 0x010501f5, 0x00f70212, 0x00e90232, ++ 0x00dc0253, 0x00d00276, 0x00c4029c, 0x00b902c3, ++ 0x00af02ed, 0x00a5031a, 0x009c0349, 0x0093037a, ++ 0x008b03af, 0x008303e7, 0x007c0422, 0x00750461, ++ 0x006e04a3, 0x006804ea, 0x00620534, 0x005d0583, ++ 0x005805d7, 0x0053062f, 0x004e068d, 0x004a06f1 ++}; ++ ++static u32 nphy_tpc_txgain_rev3[] = { ++ 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, ++ 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, ++ 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, ++ 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037, ++ 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e, ++ 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037, ++ 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e, ++ 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037, ++ 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e, ++ 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037, ++ 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e, ++ 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037, ++ 0x19410044, 0x19410042, 0x19410040, 0x1941003e, ++ 0x1941003c, 0x1941003b, 0x19410039, 0x19410037, ++ 0x18410044, 0x18410042, 0x18410040, 0x1841003e, ++ 0x1841003c, 0x1841003b, 0x18410039, 0x18410037, ++ 0x17410044, 0x17410042, 0x17410040, 0x1741003e, ++ 0x1741003c, 0x1741003b, 0x17410039, 0x17410037, ++ 0x16410044, 0x16410042, 0x16410040, 0x1641003e, ++ 0x1641003c, 0x1641003b, 0x16410039, 0x16410037, ++ 0x15410044, 0x15410042, 0x15410040, 0x1541003e, ++ 0x1541003c, 0x1541003b, 0x15410039, 0x15410037, ++ 0x14410044, 0x14410042, 0x14410040, 0x1441003e, ++ 0x1441003c, 0x1441003b, 0x14410039, 0x14410037, ++ 0x13410044, 0x13410042, 0x13410040, 0x1341003e, ++ 0x1341003c, 0x1341003b, 0x13410039, 0x13410037, ++ 0x12410044, 0x12410042, 0x12410040, 0x1241003e, ++ 0x1241003c, 0x1241003b, 0x12410039, 0x12410037, ++ 0x11410044, 0x11410042, 0x11410040, 0x1141003e, ++ 0x1141003c, 0x1141003b, 0x11410039, 0x11410037, ++ 0x10410044, 0x10410042, 0x10410040, 0x1041003e, ++ 0x1041003c, 0x1041003b, 0x10410039, 0x10410037 ++}; ++ ++static u32 nphy_tpc_txgain_HiPwrEPA[] = { ++ 0x0f410044, 0x0f410042, 0x0f410040, 0x0f41003e, ++ 0x0f41003c, 0x0f41003b, 0x0f410039, 0x0f410037, ++ 0x0e410044, 0x0e410042, 0x0e410040, 0x0e41003e, ++ 0x0e41003c, 0x0e41003b, 0x0e410039, 0x0e410037, ++ 0x0d410044, 0x0d410042, 0x0d410040, 0x0d41003e, ++ 0x0d41003c, 0x0d41003b, 0x0d410039, 0x0d410037, ++ 0x0c410044, 0x0c410042, 0x0c410040, 0x0c41003e, ++ 0x0c41003c, 0x0c41003b, 0x0c410039, 0x0c410037, ++ 0x0b410044, 0x0b410042, 0x0b410040, 0x0b41003e, ++ 0x0b41003c, 0x0b41003b, 0x0b410039, 0x0b410037, ++ 0x0a410044, 0x0a410042, 0x0a410040, 0x0a41003e, ++ 0x0a41003c, 0x0a41003b, 0x0a410039, 0x0a410037, ++ 0x09410044, 0x09410042, 0x09410040, 0x0941003e, ++ 0x0941003c, 0x0941003b, 0x09410039, 0x09410037, ++ 0x08410044, 0x08410042, 0x08410040, 0x0841003e, ++ 0x0841003c, 0x0841003b, 0x08410039, 0x08410037, ++ 0x07410044, 0x07410042, 0x07410040, 0x0741003e, ++ 0x0741003c, 0x0741003b, 0x07410039, 0x07410037, ++ 0x06410044, 0x06410042, 0x06410040, 0x0641003e, ++ 0x0641003c, 0x0641003b, 0x06410039, 0x06410037, ++ 0x05410044, 0x05410042, 0x05410040, 0x0541003e, ++ 0x0541003c, 0x0541003b, 0x05410039, 0x05410037, ++ 0x04410044, 0x04410042, 0x04410040, 0x0441003e, ++ 0x0441003c, 0x0441003b, 0x04410039, 0x04410037, ++ 0x03410044, 0x03410042, 0x03410040, 0x0341003e, ++ 0x0341003c, 0x0341003b, 0x03410039, 0x03410037, ++ 0x02410044, 0x02410042, 0x02410040, 0x0241003e, ++ 0x0241003c, 0x0241003b, 0x02410039, 0x02410037, ++ 0x01410044, 0x01410042, 0x01410040, 0x0141003e, ++ 0x0141003c, 0x0141003b, 0x01410039, 0x01410037, ++ 0x00410044, 0x00410042, 0x00410040, 0x0041003e, ++ 0x0041003c, 0x0041003b, 0x00410039, 0x00410037 ++}; ++ ++static u32 nphy_tpc_txgain_epa_2057rev3[] = { ++ 0x80f90040, 0x80e10040, 0x80e1003c, 0x80c9003d, ++ 0x80b9003c, 0x80a9003d, 0x80a1003c, 0x8099003b, ++ 0x8091003b, 0x8089003a, 0x8081003a, 0x80790039, ++ 0x80710039, 0x8069003a, 0x8061003b, 0x8059003d, ++ 0x8051003f, 0x80490042, 0x8049003e, 0x8049003b, ++ 0x8041003e, 0x8041003b, 0x8039003e, 0x8039003b, ++ 0x80390038, 0x80390035, 0x8031003a, 0x80310036, ++ 0x80310033, 0x8029003a, 0x80290037, 0x80290034, ++ 0x80290031, 0x80210039, 0x80210036, 0x80210033, ++ 0x80210030, 0x8019003c, 0x80190039, 0x80190036, ++ 0x80190033, 0x80190030, 0x8019002d, 0x8019002b, ++ 0x80190028, 0x8011003a, 0x80110036, 0x80110033, ++ 0x80110030, 0x8011002e, 0x8011002b, 0x80110029, ++ 0x80110027, 0x80110024, 0x80110022, 0x80110020, ++ 0x8011001f, 0x8011001d, 0x8009003a, 0x80090037, ++ 0x80090034, 0x80090031, 0x8009002e, 0x8009002c, ++ 0x80090029, 0x80090027, 0x80090025, 0x80090023, ++ 0x80090021, 0x8009001f, 0x8009001d, 0x8009011d, ++ 0x8009021d, 0x8009031d, 0x8009041d, 0x8009051d, ++ 0x8009061d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, ++ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d ++}; ++ ++static u32 nphy_tpc_txgain_epa_2057rev5[] = { ++ 0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d, ++ 0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b, ++ 0x1091003b, 0x1089003a, 0x1081003a, 0x10790039, ++ 0x10710039, 0x1069003a, 0x1061003b, 0x1059003d, ++ 0x1051003f, 0x10490042, 0x1049003e, 0x1049003b, ++ 0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b, ++ 0x10390038, 0x10390035, 0x1031003a, 0x10310036, ++ 0x10310033, 0x1029003a, 0x10290037, 0x10290034, ++ 0x10290031, 0x10210039, 0x10210036, 0x10210033, ++ 0x10210030, 0x1019003c, 0x10190039, 0x10190036, ++ 0x10190033, 0x10190030, 0x1019002d, 0x1019002b, ++ 0x10190028, 0x1011003a, 0x10110036, 0x10110033, ++ 0x10110030, 0x1011002e, 0x1011002b, 0x10110029, ++ 0x10110027, 0x10110024, 0x10110022, 0x10110020, ++ 0x1011001f, 0x1011001d, 0x1009003a, 0x10090037, ++ 0x10090034, 0x10090031, 0x1009002e, 0x1009002c, ++ 0x10090029, 0x10090027, 0x10090025, 0x10090023, ++ 0x10090021, 0x1009001f, 0x1009001d, 0x1009001b, ++ 0x1009001a, 0x10090018, 0x10090017, 0x10090016, ++ 0x10090015, 0x10090013, 0x10090012, 0x10090011, ++ 0x10090010, 0x1009000f, 0x1009000f, 0x1009000e, ++ 0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b, ++ 0x1009000a, 0x1009000a, 0x10090009, 0x10090009, ++ 0x10090008, 0x10090008, 0x10090007, 0x10090007, ++ 0x10090007, 0x10090006, 0x10090006, 0x10090005, ++ 0x10090005, 0x10090005, 0x10090005, 0x10090004, ++ 0x10090004, 0x10090004, 0x10090004, 0x10090003, ++ 0x10090003, 0x10090003, 0x10090003, 0x10090003, ++ 0x10090003, 0x10090002, 0x10090002, 0x10090002, ++ 0x10090002, 0x10090002, 0x10090002, 0x10090002, ++ 0x10090002, 0x10090002, 0x10090001, 0x10090001, ++ 0x10090001, 0x10090001, 0x10090001, 0x10090001 ++}; ++ ++static u32 nphy_tpc_5GHz_txgain_rev3[] = { ++ 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, ++ 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, ++ 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, ++ 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037, ++ 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e, ++ 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037, ++ 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e, ++ 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037, ++ 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e, ++ 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037, ++ 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e, ++ 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037, ++ 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e, ++ 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037, ++ 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e, ++ 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037, ++ 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e, ++ 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037, ++ 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e, ++ 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037, ++ 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e, ++ 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037, ++ 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e, ++ 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037, ++ 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e, ++ 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037, ++ 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e, ++ 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037, ++ 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e, ++ 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037, ++ 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e, ++ 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037 ++}; ++ ++static u32 nphy_tpc_5GHz_txgain_rev4[] = { ++ 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, ++ 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, ++ 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, ++ 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037, ++ 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e, ++ 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037, ++ 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e, ++ 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037, ++ 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e, ++ 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037, ++ 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e, ++ 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037, ++ 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e, ++ 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037, ++ 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e, ++ 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037, ++ 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e, ++ 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037, ++ 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e, ++ 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037, ++ 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e, ++ 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037, ++ 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e, ++ 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038, ++ 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e, ++ 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037, ++ 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e, ++ 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037, ++ 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e, ++ 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037, ++ 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c, ++ 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034 ++}; ++ ++static u32 nphy_tpc_5GHz_txgain_rev5[] = { ++ 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, ++ 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, ++ 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, ++ 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a, ++ 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e, ++ 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a, ++ 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e, ++ 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037, ++ 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040, ++ 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a, ++ 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c, ++ 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038, ++ 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b, ++ 0x09620039, 0x09620037, 0x09620035, 0x09620033, ++ 0x08620044, 0x08620042, 0x08620040, 0x0862003e, ++ 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039, ++ 0x07620043, 0x07620042, 0x07620040, 0x0762003f, ++ 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039, ++ 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b, ++ 0x06620039, 0x06620037, 0x06620035, 0x06620033, ++ 0x05620046, 0x05620044, 0x05620042, 0x05620040, ++ 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039, ++ 0x04620044, 0x04620042, 0x04620040, 0x0462003e, ++ 0x0462003c, 0x0462003b, 0x04620039, 0x04620038, ++ 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039, ++ 0x03620038, 0x03620037, 0x03620035, 0x03620033, ++ 0x0262004c, 0x0262004a, 0x02620048, 0x02620047, ++ 0x02620046, 0x02620044, 0x02620043, 0x02620042, ++ 0x0162004a, 0x01620048, 0x01620046, 0x01620044, ++ 0x01620043, 0x01620042, 0x01620041, 0x01620040, ++ 0x00620042, 0x00620040, 0x0062003e, 0x0062003c, ++ 0x0062003b, 0x00620039, 0x00620037, 0x00620035 ++}; ++ ++static u32 nphy_tpc_5GHz_txgain_HiPwrEPA[] = { ++ 0x2ff10044, 0x2ff10042, 0x2ff10040, 0x2ff1003e, ++ 0x2ff1003c, 0x2ff1003b, 0x2ff10039, 0x2ff10037, ++ 0x2ef10044, 0x2ef10042, 0x2ef10040, 0x2ef1003e, ++ 0x2ef1003c, 0x2ef1003b, 0x2ef10039, 0x2ef10037, ++ 0x2df10044, 0x2df10042, 0x2df10040, 0x2df1003e, ++ 0x2df1003c, 0x2df1003b, 0x2df10039, 0x2df10037, ++ 0x2cf10044, 0x2cf10042, 0x2cf10040, 0x2cf1003e, ++ 0x2cf1003c, 0x2cf1003b, 0x2cf10039, 0x2cf10037, ++ 0x2bf10044, 0x2bf10042, 0x2bf10040, 0x2bf1003e, ++ 0x2bf1003c, 0x2bf1003b, 0x2bf10039, 0x2bf10037, ++ 0x2af10044, 0x2af10042, 0x2af10040, 0x2af1003e, ++ 0x2af1003c, 0x2af1003b, 0x2af10039, 0x2af10037, ++ 0x29f10044, 0x29f10042, 0x29f10040, 0x29f1003e, ++ 0x29f1003c, 0x29f1003b, 0x29f10039, 0x29f10037, ++ 0x28f10044, 0x28f10042, 0x28f10040, 0x28f1003e, ++ 0x28f1003c, 0x28f1003b, 0x28f10039, 0x28f10037, ++ 0x27f10044, 0x27f10042, 0x27f10040, 0x27f1003e, ++ 0x27f1003c, 0x27f1003b, 0x27f10039, 0x27f10037, ++ 0x26f10044, 0x26f10042, 0x26f10040, 0x26f1003e, ++ 0x26f1003c, 0x26f1003b, 0x26f10039, 0x26f10037, ++ 0x25f10044, 0x25f10042, 0x25f10040, 0x25f1003e, ++ 0x25f1003c, 0x25f1003b, 0x25f10039, 0x25f10037, ++ 0x24f10044, 0x24f10042, 0x24f10040, 0x24f1003e, ++ 0x24f1003c, 0x24f1003b, 0x24f10039, 0x24f10038, ++ 0x23f10041, 0x23f10040, 0x23f1003f, 0x23f1003e, ++ 0x23f1003c, 0x23f1003b, 0x23f10039, 0x23f10037, ++ 0x22f10044, 0x22f10042, 0x22f10040, 0x22f1003e, ++ 0x22f1003c, 0x22f1003b, 0x22f10039, 0x22f10037, ++ 0x21f10044, 0x21f10042, 0x21f10040, 0x21f1003e, ++ 0x21f1003c, 0x21f1003b, 0x21f10039, 0x21f10037, ++ 0x20d10043, 0x20d10041, 0x20d1003e, 0x20d1003c, ++ 0x20d1003a, 0x20d10038, 0x20d10036, 0x20d10034 ++}; ++ ++static u8 ant_sw_ctrl_tbl_rev8_2o3[] = { 0x14, 0x18 }; ++static u8 ant_sw_ctrl_tbl_rev8[] = { 0x4, 0x8, 0x4, 0x8, 0x11, 0x12 }; ++static u8 ant_sw_ctrl_tbl_rev8_2057v7_core0[] = { ++ 0x09, 0x0a, 0x15, 0x16, 0x09, 0x0a ++}; ++static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = { ++ 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x16 ++}; ++ ++bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ u32 phybist0, phybist1, phybist2, phybist3, phybist4; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 16)) ++ return true; ++ ++ phybist0 = read_phy_reg(pi, 0x0e); ++ phybist1 = read_phy_reg(pi, 0x0f); ++ phybist2 = read_phy_reg(pi, 0xea); ++ phybist3 = read_phy_reg(pi, 0xeb); ++ phybist4 = read_phy_reg(pi, 0x156); ++ ++ if ((phybist0 == 0) && (phybist1 == 0x4000) && (phybist2 == 0x1fe0) && ++ (phybist3 == 0) && (phybist4 == 0)) ++ return true; ++ ++ return false; ++} ++ ++static void wlc_phy_bphy_init_nphy(struct brcms_phy *pi) ++{ ++ u16 addr, val; ++ ++ val = 0x1e1f; ++ for (addr = (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT); ++ addr <= (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT_END); addr++) { ++ write_phy_reg(pi, addr, val); ++ if (addr == (NPHY_TO_BPHY_OFF + 0x97)) ++ val = 0x3e3f; ++ else ++ val -= 0x0202; ++ } ++ ++ write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_STEP, 0x668); ++} ++ ++void ++wlc_phy_table_write_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset, ++ u32 width, const void *data) ++{ ++ struct phytbl_info tbl; ++ ++ tbl.tbl_id = id; ++ tbl.tbl_len = len; ++ tbl.tbl_offset = offset; ++ tbl.tbl_width = width; ++ tbl.tbl_ptr = data; ++ wlc_phy_write_table_nphy(pi, &tbl); ++} ++ ++void ++wlc_phy_table_read_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset, ++ u32 width, void *data) ++{ ++ struct phytbl_info tbl; ++ ++ tbl.tbl_id = id; ++ tbl.tbl_len = len; ++ tbl.tbl_offset = offset; ++ tbl.tbl_width = width; ++ tbl.tbl_ptr = data; ++ wlc_phy_read_table_nphy(pi, &tbl); ++} ++ ++static void ++wlc_phy_static_table_download_nphy(struct brcms_phy *pi) ++{ ++ uint idx; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 16)) { ++ for (idx = 0; idx < mimophytbl_info_sz_rev16; idx++) ++ wlc_phy_write_table_nphy(pi, ++ &mimophytbl_info_rev16[idx]); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (idx = 0; idx < mimophytbl_info_sz_rev7; idx++) ++ wlc_phy_write_table_nphy(pi, ++ &mimophytbl_info_rev7[idx]); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ for (idx = 0; idx < mimophytbl_info_sz_rev3; idx++) ++ wlc_phy_write_table_nphy(pi, ++ &mimophytbl_info_rev3[idx]); ++ } else { ++ for (idx = 0; idx < mimophytbl_info_sz_rev0; idx++) ++ wlc_phy_write_table_nphy(pi, ++ &mimophytbl_info_rev0[idx]); ++ } ++} ++ ++static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi) ++{ ++ uint idx = 0; ++ u8 antswctrllut; ++ ++ if (pi->phy_init_por) ++ wlc_phy_static_table_download_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ antswctrllut = CHSPEC_IS2G(pi->radio_chanspec) ? ++ pi->srom_fem2g.antswctrllut : pi->srom_fem5g. ++ antswctrllut; ++ ++ switch (antswctrllut) { ++ case 0: ++ ++ break; ++ ++ case 1: ++ ++ if (pi->aa2g == 7) ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x21, 8, ++ &ant_sw_ctrl_tbl_rev8_2o3[0]); ++ else ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x21, 8, ++ &ant_sw_ctrl_tbl_rev8 ++ [0]); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x25, 8, ++ &ant_sw_ctrl_tbl_rev8[2]); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x29, 8, ++ &ant_sw_ctrl_tbl_rev8[4]); ++ break; ++ ++ case 2: ++ ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x1, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core0[0]); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x5, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core0[2]); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x9, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core0[4]); ++ ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x21, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core1[0]); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x25, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core1[2]); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 2, 0x29, 8, ++ &ant_sw_ctrl_tbl_rev8_2057v7_core1[4]); ++ break; ++ ++ default: ++ break; ++ } ++ ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ for (idx = 0; idx < mimophytbl_info_sz_rev3_volatile; idx++) { ++ ++ if (idx == ANT_SWCTRL_TBL_REV3_IDX) { ++ antswctrllut = ++ CHSPEC_IS2G(pi->radio_chanspec) ? ++ pi->srom_fem2g.antswctrllut : ++ pi->srom_fem5g.antswctrllut; ++ switch (antswctrllut) { ++ case 0: ++ wlc_phy_write_table_nphy( ++ pi, ++ &mimophytbl_info_rev3_volatile ++ [idx]); ++ break; ++ case 1: ++ wlc_phy_write_table_nphy( ++ pi, ++ &mimophytbl_info_rev3_volatile1 ++ [idx]); ++ break; ++ case 2: ++ wlc_phy_write_table_nphy( ++ pi, ++ &mimophytbl_info_rev3_volatile2 ++ [idx]); ++ break; ++ case 3: ++ wlc_phy_write_table_nphy( ++ pi, ++ &mimophytbl_info_rev3_volatile3 ++ [idx]); ++ break; ++ default: ++ break; ++ } ++ } else { ++ wlc_phy_write_table_nphy( ++ pi, ++ &mimophytbl_info_rev3_volatile[idx]); ++ } ++ } ++ } else { ++ for (idx = 0; idx < mimophytbl_info_sz_rev0_volatile; idx++) ++ wlc_phy_write_table_nphy(pi, ++ &mimophytbl_info_rev0_volatile ++ [idx]); ++ } ++} ++ ++static void ++wlc_phy_write_txmacreg_nphy(struct brcms_phy *pi, u16 holdoff, u16 delay) ++{ ++ write_phy_reg(pi, 0x77, holdoff); ++ write_phy_reg(pi, 0xb4, delay); ++} ++ ++void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs) ++{ ++ u16 holdoff, delay; ++ ++ if (rifs) { ++ ++ holdoff = 0x10; ++ delay = 0x258; ++ } else { ++ ++ holdoff = 0x15; ++ delay = 0x320; ++ } ++ ++ wlc_phy_write_txmacreg_nphy(pi, holdoff, delay); ++ ++ if (pi && pi->sh && (pi->sh->_rifs_phy != rifs)) ++ pi->sh->_rifs_phy = rifs; ++} ++ ++static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi) ++{ ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ pi->nphy_txpwrctrl = PHY_TPC_HW_ON; ++ pi->phy_5g_pwrgain = true; ++ return; ++ } ++ ++ pi->nphy_txpwrctrl = PHY_TPC_HW_OFF; ++ pi->phy_5g_pwrgain = false; ++ ++ if ((pi->sh->boardflags2 & BFL2_TXPWRCTRL_EN) && ++ NREV_GE(pi->pubpi.phy_rev, 2) && (pi->sh->sromrev >= 4)) ++ pi->nphy_txpwrctrl = PHY_TPC_HW_ON; ++ else if ((pi->sh->sromrev >= 4) ++ && (pi->sh->boardflags2 & BFL2_5G_PWRGAIN)) ++ pi->phy_5g_pwrgain = true; ++} ++ ++static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) ++{ ++ u16 bw40po, cddpo, stbcpo, bwduppo; ++ uint band_num; ++ struct phy_shim_info *shim = pi->sh->physhim; ++ ++ if (pi->sh->sromrev >= 9) ++ return; ++ ++ bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO); ++ pi->bw402gpo = bw40po & 0xf; ++ pi->bw405gpo = (bw40po & 0xf0) >> 4; ++ pi->bw405glpo = (bw40po & 0xf00) >> 8; ++ pi->bw405ghpo = (bw40po & 0xf000) >> 12; ++ ++ cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO); ++ pi->cdd2gpo = cddpo & 0xf; ++ pi->cdd5gpo = (cddpo & 0xf0) >> 4; ++ pi->cdd5glpo = (cddpo & 0xf00) >> 8; ++ pi->cdd5ghpo = (cddpo & 0xf000) >> 12; ++ ++ stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO); ++ pi->stbc2gpo = stbcpo & 0xf; ++ pi->stbc5gpo = (stbcpo & 0xf0) >> 4; ++ pi->stbc5glpo = (stbcpo & 0xf00) >> 8; ++ pi->stbc5ghpo = (stbcpo & 0xf000) >> 12; ++ ++ bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO); ++ pi->bwdup2gpo = bwduppo & 0xf; ++ pi->bwdup5gpo = (bwduppo & 0xf0) >> 4; ++ pi->bwdup5glpo = (bwduppo & 0xf00) >> 8; ++ pi->bwdup5ghpo = (bwduppo & 0xf000) >> 12; ++ ++ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); ++ band_num++) { ++ switch (band_num) { ++ case 0: ++ ++ pi->nphy_txpid2g[PHY_CORE_0] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID2GA0); ++ pi->nphy_txpid2g[PHY_CORE_1] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID2GA1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP2GA0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP2GA1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW0A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW0A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW1A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW1A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW2A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA2GW2A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g = ++ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g = ++ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1); ++ ++ pi->cck2gpo = (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_CCK2GPO); ++ ++ pi->ofdm2gpo = ++ (u32) wlapi_getintvar(shim, ++ BRCMS_SROM_OFDM2GPO); ++ ++ pi->mcs2gpo[0] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO0); ++ pi->mcs2gpo[1] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO1); ++ pi->mcs2gpo[2] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO2); ++ pi->mcs2gpo[3] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO3); ++ pi->mcs2gpo[4] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO4); ++ pi->mcs2gpo[5] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO5); ++ pi->mcs2gpo[6] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO6); ++ pi->mcs2gpo[7] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS2GPO7); ++ break; ++ case 1: ++ ++ pi->nphy_txpid5g[PHY_CORE_0] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GA0); ++ pi->nphy_txpid5g[PHY_CORE_1] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GA1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm = ++ (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP5GA1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW0A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW0A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW1A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW1A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW2A0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GW2A1); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm = ++ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm = ++ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1); ++ ++ pi->ofdm5gpo = ++ (u32) wlapi_getintvar(shim, ++ BRCMS_SROM_OFDM5GPO); ++ ++ pi->mcs5gpo[0] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO0); ++ pi->mcs5gpo[1] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO1); ++ pi->mcs5gpo[2] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO2); ++ pi->mcs5gpo[3] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO3); ++ pi->mcs5gpo[4] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO4); ++ pi->mcs5gpo[5] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO5); ++ pi->mcs5gpo[6] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO6); ++ pi->mcs5gpo[7] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GPO7); ++ break; ++ case 2: ++ ++ pi->nphy_txpid5gl[0] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GLA0); ++ pi->nphy_txpid5gl[1] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GLA1); ++ pi->nphy_pwrctrl_info[0].max_pwr_5gl = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP5GLA0); ++ pi->nphy_pwrctrl_info[1].max_pwr_5gl = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP5GLA1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW0A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW0A1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW1A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW1A1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW2A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GLW2A1); ++ pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0; ++ pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0; ++ ++ pi->ofdm5glpo = ++ (u32) wlapi_getintvar(shim, ++ BRCMS_SROM_OFDM5GLPO); ++ ++ pi->mcs5glpo[0] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO0); ++ pi->mcs5glpo[1] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO1); ++ pi->mcs5glpo[2] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO2); ++ pi->mcs5glpo[3] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO3); ++ pi->mcs5glpo[4] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO4); ++ pi->mcs5glpo[5] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO5); ++ pi->mcs5glpo[6] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO6); ++ pi->mcs5glpo[7] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GLPO7); ++ break; ++ case 3: ++ ++ pi->nphy_txpid5gh[0] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GHA0); ++ pi->nphy_txpid5gh[1] = ++ (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TXPID5GHA1); ++ pi->nphy_pwrctrl_info[0].max_pwr_5gh = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP5GHA0); ++ pi->nphy_pwrctrl_info[1].max_pwr_5gh = ++ (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_MAXP5GHA1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW0A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW0A1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW1A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW1A1); ++ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW2A0); ++ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 = ++ (s16) wlapi_getintvar(shim, ++ BRCMS_SROM_PA5GHW2A1); ++ pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0; ++ pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0; ++ ++ pi->ofdm5ghpo = ++ (u32) wlapi_getintvar(shim, ++ BRCMS_SROM_OFDM5GHPO); ++ ++ pi->mcs5ghpo[0] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO0); ++ pi->mcs5ghpo[1] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO1); ++ pi->mcs5ghpo[2] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO2); ++ pi->mcs5ghpo[3] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO3); ++ pi->mcs5ghpo[4] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO4); ++ pi->mcs5ghpo[5] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO5); ++ pi->mcs5ghpo[6] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO6); ++ pi->mcs5ghpo[7] = ++ (u16) wlapi_getintvar(shim, ++ BRCMS_SROM_MCS5GHPO7); ++ break; ++ } ++ } ++ ++ wlc_phy_txpwr_apply_nphy(pi); ++} ++ ++static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) ++{ ++ struct phy_shim_info *shim = pi->sh->physhim; ++ ++ pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH); ++ pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G); ++ pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G); ++ ++ pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TSSIPOS2G); ++ pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_EXTPAGAIN2G); ++ pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_PDETRANGE2G); ++ pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); ++ pi->srom_fem2g.antswctrllut = ++ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); ++ ++ pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_TSSIPOS5G); ++ pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_EXTPAGAIN5G); ++ pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim, ++ BRCMS_SROM_PDETRANGE5G); ++ pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G); ++ if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G)) ++ pi->srom_fem5g.antswctrllut = ++ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G); ++ else ++ pi->srom_fem5g.antswctrllut = ++ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); ++ ++ wlc_phy_txpower_ipa_upd(pi); ++ ++ pi->phy_txcore_disable_temp = ++ (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH); ++ if (pi->phy_txcore_disable_temp == 0) ++ pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; ++ ++ pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim, ++ BRCMS_SROM_TEMPOFFSET); ++ if (pi->phy_tempsense_offset != 0) { ++ if (pi->phy_tempsense_offset > ++ (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET)) ++ pi->phy_tempsense_offset = NPHY_SROM_MAXTEMPOFFSET; ++ else if (pi->phy_tempsense_offset < (NPHY_SROM_TEMPSHIFT + ++ NPHY_SROM_MINTEMPOFFSET)) ++ pi->phy_tempsense_offset = NPHY_SROM_MINTEMPOFFSET; ++ else ++ pi->phy_tempsense_offset -= NPHY_SROM_TEMPSHIFT; ++ } ++ ++ pi->phy_txcore_enable_temp = ++ pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP; ++ ++ pi->phycal_tempdelta = ++ (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA); ++ if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA) ++ pi->phycal_tempdelta = 0; ++ ++ wlc_phy_txpwr_srom_read_ppr_nphy(pi); ++ ++ return true; ++} ++ ++bool wlc_phy_attach_nphy(struct brcms_phy *pi) ++{ ++ uint i; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 6)) ++ pi->phyhang_avoid = true; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ pi->nphy_gband_spurwar_en = true; ++ if (pi->sh->boardflags2 & BFL2_SPUR_WAR) ++ pi->nphy_aband_spurwar_en = true; ++ } ++ if (NREV_GE(pi->pubpi.phy_rev, 6) && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ if (pi->sh->boardflags2 & BFL2_2G_SPUR_WAR) ++ pi->nphy_gband_spurwar2_en = true; ++ } ++ ++ pi->n_preamble_override = AUTO; ++ if (NREV_IS(pi->pubpi.phy_rev, 3) || NREV_IS(pi->pubpi.phy_rev, 4)) ++ pi->n_preamble_override = BRCMS_N_PREAMBLE_MIXEDMODE; ++ ++ pi->nphy_txrx_chain = AUTO; ++ pi->phy_scraminit = AUTO; ++ ++ pi->nphy_rxcalparams = 0x010100B5; ++ ++ pi->nphy_perical = PHY_PERICAL_MPHASE; ++ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE; ++ pi->mphase_txcal_numcmds = MPHASE_TXCAL_NUMCMDS; ++ ++ pi->nphy_gain_boost = true; ++ pi->nphy_elna_gain_config = false; ++ pi->radio_is_on = false; ++ ++ for (i = 0; i < pi->pubpi.phy_corenum; i++) ++ pi->nphy_txpwrindex[i].index = AUTO; ++ ++ wlc_phy_txpwrctrl_config_nphy(pi); ++ if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON) ++ pi->hwpwrctrl_capable = true; ++ ++ pi->pi_fptr.init = wlc_phy_init_nphy; ++ pi->pi_fptr.calinit = wlc_phy_cal_init_nphy; ++ pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy; ++ pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy; ++ ++ if (!wlc_phy_txpwr_srom_read_nphy(pi)) ++ return false; ++ ++ return true; ++} ++ ++static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn) ++{ ++ s32 rfpwr_offset = 0; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ rfpwr_offset = (s16) ++ nphy_papd_padgain_dlt_2g_2057rev3n4 ++ [pad_gn]; ++ else if (pi->pubpi.radiorev == 5) ++ rfpwr_offset = (s16) ++ nphy_papd_padgain_dlt_2g_2057rev5 ++ [pad_gn]; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == ++ 8)) ++ rfpwr_offset = (s16) ++ nphy_papd_padgain_dlt_2g_2057rev7 ++ [pad_gn]; ++ } else { ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ rfpwr_offset = (s16) ++ nphy_papd_pgagain_dlt_5g_2057 ++ [pga_gn]; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == ++ 8)) ++ rfpwr_offset = (s16) ++ nphy_papd_pgagain_dlt_5g_2057rev7 ++ [pga_gn]; ++ } ++ return rfpwr_offset; ++} ++ ++static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble) ++{ ++ bool gf_preamble = false; ++ u16 val; ++ ++ if (preamble == BRCMS_N_PREAMBLE_GF) ++ gf_preamble = true; ++ ++ val = read_phy_reg(pi, 0xed); ++ ++ val |= RX_GF_MM_AUTO; ++ val &= ~RX_GF_OR_MM; ++ if (gf_preamble) ++ val |= RX_GF_OR_MM; ++ ++ write_phy_reg(pi, 0xed, val); ++} ++ ++static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi) ++{ ++ int j, type; ++ u16 addr_offset[] = { 0x186, 0x195, 0x2c5}; ++ ++ for (type = 0; type < 3; type++) { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, addr_offset[type] + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]); ++ } ++ ++ if (pi->bw == WL_CHANSPEC_BW_40) { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, 0x186 + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]); ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, 0x186 + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[5][j]); ++ } ++ ++ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, 0x2c5 + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[6][j]); ++ } ++ } ++} ++ ++static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi) ++{ ++ int j; ++ ++ if (pi->bw == WL_CHANSPEC_BW_40) { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, 0x195 + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[4][j]); ++ } else { ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, 0x186 + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]); ++ } ++} ++ ++static void ++wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys, ++ u8 len) ++{ ++ u32 t1_offset, t2_offset; ++ u8 ctr; ++ u8 end_event = ++ NREV_GE(pi->pubpi.phy_rev, ++ 3) ? NPHY_REV3_RFSEQ_CMD_END : NPHY_RFSEQ_CMD_END; ++ u8 end_dly = 1; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ t1_offset = cmd << 4; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t1_offset, 8, ++ events); ++ t2_offset = t1_offset + 0x080; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t2_offset, 8, ++ dlys); ++ ++ for (ctr = len; ctr < 16; ctr++) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, ++ t1_offset + ctr, 8, &end_event); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, ++ t2_offset + ctr, 8, &end_dly); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset) ++{ ++ u16 lpf_bw_ctl_val = 0; ++ u16 rx2tx_lpf_rc_lut_offset = 0; ++ ++ if (offset == 0) { ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ rx2tx_lpf_rc_lut_offset = 0x159; ++ else ++ rx2tx_lpf_rc_lut_offset = 0x154; ++ } else { ++ rx2tx_lpf_rc_lut_offset = offset; ++ } ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, ++ (u32) rx2tx_lpf_rc_lut_offset, 16, ++ &lpf_bw_ctl_val); ++ ++ lpf_bw_ctl_val = lpf_bw_ctl_val & 0x7; ++ ++ return lpf_bw_ctl_val; ++} ++ ++static void ++wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value, ++ u8 core_mask, u8 off, u8 override_id) ++{ ++ u8 core_num; ++ u16 addr = 0, en_addr = 0, val_addr = 0, en_mask = 0, val_mask = 0; ++ u8 val_shift = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ en_mask = field; ++ for (core_num = 0; core_num < 2; core_num++) { ++ if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID0) { ++ ++ switch (field) { ++ case (0x1 << 2): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 1); ++ val_shift = 1; ++ break; ++ case (0x1 << 3): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 2); ++ val_shift = 2; ++ break; ++ case (0x1 << 4): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 4); ++ val_shift = 4; ++ break; ++ case (0x1 << 5): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 5); ++ val_shift = 5; ++ break; ++ case (0x1 << 6): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 6); ++ val_shift = 6; ++ break; ++ case (0x1 << 7): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : ++ 0x7d; ++ val_mask = (0x1 << 7); ++ val_shift = 7; ++ break; ++ case (0x1 << 10): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0xf8 : ++ 0xfa; ++ val_mask = (0x7 << 4); ++ val_shift = 4; ++ break; ++ case (0x1 << 11): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7b : ++ 0x7e; ++ val_mask = (0xffff << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 12): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7c : ++ 0x7f; ++ val_mask = (0xffff << 0); ++ val_shift = 0; ++ break; ++ case (0x3 << 13): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x348 : ++ 0x349; ++ val_mask = (0xff << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 13): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x348 : ++ 0x349; ++ val_mask = (0xf << 0); ++ val_shift = 0; ++ break; ++ default: ++ addr = 0xffff; ++ break; ++ } ++ } else if (override_id == ++ NPHY_REV7_RFCTRLOVERRIDE_ID1) { ++ ++ switch (field) { ++ case (0x1 << 1): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 1); ++ val_shift = 1; ++ break; ++ case (0x1 << 3): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 3); ++ val_shift = 3; ++ break; ++ case (0x1 << 5): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 5); ++ val_shift = 5; ++ break; ++ case (0x1 << 4): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 4); ++ val_shift = 4; ++ break; ++ case (0x1 << 2): ++ ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 2); ++ val_shift = 2; ++ break; ++ case (0x1 << 7): ++ ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x7 << 8); ++ val_shift = 8; ++ break; ++ case (0x1 << 11): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 14); ++ val_shift = 14; ++ break; ++ case (0x1 << 10): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 13); ++ val_shift = 13; ++ break; ++ case (0x1 << 9): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 12); ++ val_shift = 12; ++ break; ++ case (0x1 << 8): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 11); ++ val_shift = 11; ++ break; ++ case (0x1 << 6): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 6); ++ val_shift = 6; ++ break; ++ case (0x1 << 0): ++ en_addr = (core_num == 0) ? 0x342 : ++ 0x343; ++ val_addr = (core_num == 0) ? 0x340 : ++ 0x341; ++ val_mask = (0x1 << 0); ++ val_shift = 0; ++ break; ++ default: ++ addr = 0xffff; ++ break; ++ } ++ } else if (override_id == ++ NPHY_REV7_RFCTRLOVERRIDE_ID2) { ++ ++ switch (field) { ++ case (0x1 << 3): ++ en_addr = (core_num == 0) ? 0x346 : ++ 0x347; ++ val_addr = (core_num == 0) ? 0x344 : ++ 0x345; ++ val_mask = (0x1 << 3); ++ val_shift = 3; ++ break; ++ case (0x1 << 1): ++ en_addr = (core_num == 0) ? 0x346 : ++ 0x347; ++ val_addr = (core_num == 0) ? 0x344 : ++ 0x345; ++ val_mask = (0x1 << 1); ++ val_shift = 1; ++ break; ++ case (0x1 << 0): ++ en_addr = (core_num == 0) ? 0x346 : ++ 0x347; ++ val_addr = (core_num == 0) ? 0x344 : ++ 0x345; ++ val_mask = (0x1 << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 2): ++ en_addr = (core_num == 0) ? 0x346 : ++ 0x347; ++ val_addr = (core_num == 0) ? 0x344 : ++ 0x345; ++ val_mask = (0x1 << 2); ++ val_shift = 2; ++ break; ++ case (0x1 << 4): ++ en_addr = (core_num == 0) ? 0x346 : ++ 0x347; ++ val_addr = (core_num == 0) ? 0x344 : ++ 0x345; ++ val_mask = (0x1 << 4); ++ val_shift = 4; ++ break; ++ default: ++ addr = 0xffff; ++ break; ++ } ++ } ++ ++ if (off) { ++ and_phy_reg(pi, en_addr, ~en_mask); ++ and_phy_reg(pi, val_addr, ~val_mask); ++ } else { ++ ++ if ((core_mask == 0) ++ || (core_mask & (1 << core_num))) { ++ or_phy_reg(pi, en_addr, en_mask); ++ ++ if (addr != 0xffff) ++ mod_phy_reg(pi, val_addr, ++ val_mask, ++ (value << ++ val_shift)); ++ } ++ } ++ } ++ } ++} ++ ++static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi) ++{ ++ uint core; ++ int ctr; ++ s16 gain_delta[2]; ++ u8 curr_channel; ++ u16 minmax_gain[2]; ++ u16 regval[4]; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (pi->nphy_gain_boost) { ++ if ((CHSPEC_IS2G(pi->radio_chanspec))) { ++ ++ gain_delta[0] = 6; ++ gain_delta[1] = 6; ++ } else { ++ ++ curr_channel = CHSPEC_CHANNEL(pi->radio_chanspec); ++ gain_delta[0] = ++ (s16) ++ PHY_HW_ROUND(((nphy_lnagain_est0[0] * ++ curr_channel) + ++ nphy_lnagain_est0[1]), 13); ++ gain_delta[1] = ++ (s16) ++ PHY_HW_ROUND(((nphy_lnagain_est1[0] * ++ curr_channel) + ++ nphy_lnagain_est1[1]), 13); ++ } ++ } else { ++ ++ gain_delta[0] = 0; ++ gain_delta[1] = 0; ++ } ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ if (pi->nphy_elna_gain_config) { ++ ++ regval[0] = nphy_def_lnagains[2] + gain_delta[core]; ++ regval[1] = nphy_def_lnagains[3] + gain_delta[core]; ++ regval[2] = nphy_def_lnagains[3] + gain_delta[core]; ++ regval[3] = nphy_def_lnagains[3] + gain_delta[core]; ++ } else { ++ for (ctr = 0; ctr < 4; ctr++) ++ regval[ctr] = ++ nphy_def_lnagains[ctr] + ++ gain_delta[core]; ++ } ++ wlc_phy_table_write_nphy(pi, core, 4, 8, 16, regval); ++ ++ minmax_gain[core] = ++ (u16) (nphy_def_lnagains[2] + gain_delta[core] + 4); ++ } ++ ++ mod_phy_reg(pi, 0x1e, (0xff << 0), (minmax_gain[0] << 0)); ++ mod_phy_reg(pi, 0x34, (0xff << 0), (minmax_gain[1] << 0)); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void ++wlc_phy_war_force_trsw_to_R_cliplo_nphy(struct brcms_phy *pi, u8 core) ++{ ++ if (core == PHY_CORE_0) { ++ write_phy_reg(pi, 0x38, 0x4); ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ write_phy_reg(pi, 0x37, 0x0060); ++ else ++ write_phy_reg(pi, 0x37, 0x1080); ++ } else if (core == PHY_CORE_1) { ++ write_phy_reg(pi, 0x2ae, 0x4); ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ write_phy_reg(pi, 0x2ad, 0x0060); ++ else ++ write_phy_reg(pi, 0x2ad, 0x1080); ++ } ++} ++ ++static void wlc_phy_war_txchain_upd_nphy(struct brcms_phy *pi, u8 txchain) ++{ ++ u8 txchain0, txchain1; ++ ++ txchain0 = txchain & 0x1; ++ txchain1 = (txchain & 0x2) >> 1; ++ if (!txchain0) ++ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0); ++ ++ if (!txchain1) ++ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1); ++} ++ ++static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi) ++{ ++ s8 lna1_gain_db[] = { 8, 13, 17, 22 }; ++ s8 lna2_gain_db[] = { -2, 7, 11, 15 }; ++ s8 tia_gain_db[] = { -4, -1, 2, 5, 5, 5, 5, 5, 5, 5 }; ++ s8 tia_gainbits[] = { ++ 0x0, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; ++ ++ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); ++ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); ++ ++ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0)); ++ ++ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3c << 0)); ++ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3c << 0)); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x8, 8, ++ lna1_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x8, 8, ++ lna1_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, 8, ++ lna2_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, 8, ++ lna2_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8, ++ tia_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8, ++ tia_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8, ++ tia_gainbits); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8, ++ tia_gainbits); ++ ++ write_phy_reg(pi, 0x37, 0x74); ++ write_phy_reg(pi, 0x2ad, 0x74); ++ write_phy_reg(pi, 0x38, 0x18); ++ write_phy_reg(pi, 0x2ae, 0x18); ++ ++ write_phy_reg(pi, 0x2b, 0xe8); ++ write_phy_reg(pi, 0x41, 0xe8); ++ ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ ++ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x12 << 0)); ++ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x12 << 0)); ++ } else { ++ ++ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x10 << 0)); ++ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x10 << 0)); ++ } ++} ++ ++static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) ++{ ++ u16 currband; ++ s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; ++ s8 *lna1_gain_db = NULL; ++ s8 *lna1_gain_db_2 = NULL; ++ s8 *lna2_gain_db = NULL; ++ s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; ++ s8 *tia_gain_db; ++ s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; ++ s8 *tia_gainbits; ++ u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; ++ u16 *rfseq_init_gain; ++ u16 init_gaincode; ++ u16 clip1hi_gaincode; ++ u16 clip1md_gaincode = 0; ++ u16 clip1md_gaincode_B; ++ u16 clip1lo_gaincode; ++ u16 clip1lo_gaincode_B; ++ u8 crsminl_th = 0; ++ u8 crsminu_th; ++ u16 nbclip_th = 0; ++ u8 w1clip_th; ++ u16 freq; ++ s8 nvar_baseline_offset0 = 0, nvar_baseline_offset1 = 0; ++ u8 chg_nbclip_th = 0; ++ ++ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); ++ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); ++ ++ currband = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; ++ if (currband == 0) { ++ ++ lna1_gain_db = lna1G_gain_db_rev7; ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8, ++ lna1_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8, ++ lna1_gain_db); ++ ++ mod_phy_reg(pi, 0x283, (0xff << 0), (0x40 << 0)); ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3e << 0)); ++ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3e << 0)); ++ } ++ ++ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0)); ++ ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x300, (0x3f << 0), (13 << 0)); ++ mod_phy_reg(pi, 0x301, (0x3f << 0), (13 << 0)); ++ } ++ } else { ++ ++ init_gaincode = 0x9e; ++ clip1hi_gaincode = 0x9e; ++ clip1md_gaincode_B = 0x24; ++ clip1lo_gaincode = 0x8a; ++ clip1lo_gaincode_B = 8; ++ rfseq_init_gain = rfseqA_init_gain_rev7; ++ ++ tia_gain_db = tiaA_gain_db_rev7; ++ tia_gainbits = tiaA_gainbits_rev7; ++ ++ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec)); ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ ++ w1clip_th = 25; ++ clip1md_gaincode = 0x82; ++ ++ if ((freq <= 5080) || (freq == 5825)) { ++ ++ s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; ++ s8 lna1A_gain_db_2_rev7[] = { ++ 11, 17, 22, 25}; ++ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; ++ ++ crsminu_th = 0x3e; ++ lna1_gain_db = lna1A_gain_db_rev7; ++ lna1_gain_db_2 = lna1A_gain_db_2_rev7; ++ lna2_gain_db = lna2A_gain_db_rev7; ++ } else if ((freq >= 5500) && (freq <= 5700)) { ++ ++ s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; ++ s8 lna1A_gain_db_2_rev7[] = { ++ 12, 18, 22, 26}; ++ s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; ++ ++ crsminu_th = 0x45; ++ clip1md_gaincode_B = 0x14; ++ nbclip_th = 0xff; ++ chg_nbclip_th = 1; ++ lna1_gain_db = lna1A_gain_db_rev7; ++ lna1_gain_db_2 = lna1A_gain_db_2_rev7; ++ lna2_gain_db = lna2A_gain_db_rev7; ++ } else { ++ ++ s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; ++ s8 lna1A_gain_db_2_rev7[] = { ++ 12, 18, 22, 26}; ++ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; ++ ++ crsminu_th = 0x41; ++ lna1_gain_db = lna1A_gain_db_rev7; ++ lna1_gain_db_2 = lna1A_gain_db_2_rev7; ++ lna2_gain_db = lna2A_gain_db_rev7; ++ } ++ ++ if (freq <= 4920) { ++ nvar_baseline_offset0 = 5; ++ nvar_baseline_offset1 = 5; ++ } else if ((freq > 4920) && (freq <= 5320)) { ++ nvar_baseline_offset0 = 3; ++ nvar_baseline_offset1 = 5; ++ } else if ((freq > 5320) && (freq <= 5700)) { ++ nvar_baseline_offset0 = 3; ++ nvar_baseline_offset1 = 2; ++ } else { ++ nvar_baseline_offset0 = 4; ++ nvar_baseline_offset1 = 0; ++ } ++ } else { ++ ++ crsminu_th = 0x3a; ++ crsminl_th = 0x3a; ++ w1clip_th = 20; ++ ++ if ((freq >= 4920) && (freq <= 5320)) { ++ nvar_baseline_offset0 = 4; ++ nvar_baseline_offset1 = 5; ++ } else if ((freq > 5320) && (freq <= 5550)) { ++ nvar_baseline_offset0 = 4; ++ nvar_baseline_offset1 = 2; ++ } else { ++ nvar_baseline_offset0 = 5; ++ nvar_baseline_offset1 = 3; ++ } ++ } ++ ++ write_phy_reg(pi, 0x20, init_gaincode); ++ write_phy_reg(pi, 0x2a7, init_gaincode); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ pi->pubpi.phy_corenum, 0x106, 16, ++ rfseq_init_gain); ++ ++ write_phy_reg(pi, 0x22, clip1hi_gaincode); ++ write_phy_reg(pi, 0x2a9, clip1hi_gaincode); ++ ++ write_phy_reg(pi, 0x36, clip1md_gaincode_B); ++ write_phy_reg(pi, 0x2ac, clip1md_gaincode_B); ++ ++ write_phy_reg(pi, 0x37, clip1lo_gaincode); ++ write_phy_reg(pi, 0x2ad, clip1lo_gaincode); ++ write_phy_reg(pi, 0x38, clip1lo_gaincode_B); ++ write_phy_reg(pi, 0x2ae, clip1lo_gaincode_B); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8, ++ tia_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8, ++ tia_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8, ++ tia_gainbits); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8, ++ tia_gainbits); ++ ++ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0)); ++ ++ if (chg_nbclip_th == 1) { ++ write_phy_reg(pi, 0x2b, nbclip_th); ++ write_phy_reg(pi, 0x41, nbclip_th); ++ } ++ ++ mod_phy_reg(pi, 0x300, (0x3f << 0), (w1clip_th << 0)); ++ mod_phy_reg(pi, 0x301, (0x3f << 0), (w1clip_th << 0)); ++ ++ mod_phy_reg(pi, 0x2e4, ++ (0x3f << 0), (nvar_baseline_offset0 << 0)); ++ ++ mod_phy_reg(pi, 0x2e4, ++ (0x3f << 6), (nvar_baseline_offset1 << 6)); ++ ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8, ++ lna1_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8, ++ lna1_gain_db_2); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, ++ 8, lna2_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, ++ 8, lna2_gain_db); ++ ++ write_phy_reg(pi, 0x24, clip1md_gaincode); ++ write_phy_reg(pi, 0x2ab, clip1md_gaincode); ++ } else { ++ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0)); ++ } ++ } ++} ++ ++static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) ++{ ++ u16 w1th, hpf_code, currband; ++ int ctr; ++ u8 rfseq_updategainu_events[] = { ++ NPHY_RFSEQ_CMD_RX_GAIN, ++ NPHY_RFSEQ_CMD_CLR_HIQ_DIS, ++ NPHY_RFSEQ_CMD_SET_HPF_BW ++ }; ++ u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; ++ s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; ++ s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; ++ s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; ++ s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; ++ s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; ++ s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; ++ s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; ++ s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; ++ s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; ++ s8 *lna1_gain_db = NULL; ++ s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; ++ s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; ++ s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; ++ s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; ++ s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; ++ s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; ++ s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; ++ s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; ++ s8 *lna2_gain_db = NULL; ++ s8 tiaG_gain_db[] = { ++ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A }; ++ s8 tiaA_gain_db[] = { ++ 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 }; ++ s8 tiaA_gain_db_rev4[] = { ++ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; ++ s8 tiaA_gain_db_rev5[] = { ++ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; ++ s8 tiaA_gain_db_rev6[] = { ++ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; ++ s8 *tia_gain_db; ++ s8 tiaG_gainbits[] = { ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; ++ s8 tiaA_gainbits[] = { ++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 }; ++ s8 tiaA_gainbits_rev4[] = { ++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; ++ s8 tiaA_gainbits_rev5[] = { ++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; ++ s8 tiaA_gainbits_rev6[] = { ++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; ++ s8 *tia_gainbits; ++ s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; ++ s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; ++ u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; ++ u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; ++ u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; ++ u16 rfseqG_init_gain_rev5_elna[] = { ++ 0x013f, 0x013f, 0x013f, 0x013f }; ++ u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; ++ u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; ++ u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; ++ u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; ++ u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; ++ u16 rfseqA_init_gain_rev4_elna[] = { ++ 0x314f, 0x314f, 0x314f, 0x314f }; ++ u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; ++ u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; ++ u16 *rfseq_init_gain; ++ u16 initG_gaincode = 0x627e; ++ u16 initG_gaincode_rev4 = 0x527e; ++ u16 initG_gaincode_rev5 = 0x427e; ++ u16 initG_gaincode_rev5_elna = 0x027e; ++ u16 initG_gaincode_rev6 = 0x527e; ++ u16 initG_gaincode_rev6_224B0 = 0x427e; ++ u16 initG_gaincode_rev6_elna = 0x127e; ++ u16 initA_gaincode = 0x52de; ++ u16 initA_gaincode_rev4 = 0x629e; ++ u16 initA_gaincode_rev4_elna = 0x329e; ++ u16 initA_gaincode_rev5 = 0x729e; ++ u16 initA_gaincode_rev6 = 0x729e; ++ u16 init_gaincode; ++ u16 clip1hiG_gaincode = 0x107e; ++ u16 clip1hiG_gaincode_rev4 = 0x007e; ++ u16 clip1hiG_gaincode_rev5 = 0x1076; ++ u16 clip1hiG_gaincode_rev6 = 0x007e; ++ u16 clip1hiA_gaincode = 0x00de; ++ u16 clip1hiA_gaincode_rev4 = 0x029e; ++ u16 clip1hiA_gaincode_rev5 = 0x029e; ++ u16 clip1hiA_gaincode_rev6 = 0x029e; ++ u16 clip1hi_gaincode; ++ u16 clip1mdG_gaincode = 0x0066; ++ u16 clip1mdA_gaincode = 0x00ca; ++ u16 clip1mdA_gaincode_rev4 = 0x1084; ++ u16 clip1mdA_gaincode_rev5 = 0x2084; ++ u16 clip1mdA_gaincode_rev6 = 0x2084; ++ u16 clip1md_gaincode = 0; ++ u16 clip1loG_gaincode = 0x0074; ++ u16 clip1loG_gaincode_rev5[] = { ++ 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c ++ }; ++ u16 clip1loG_gaincode_rev6[] = { ++ 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e ++ }; ++ u16 clip1loG_gaincode_rev6_224B0 = 0x1074; ++ u16 clip1loA_gaincode = 0x00cc; ++ u16 clip1loA_gaincode_rev4 = 0x0086; ++ u16 clip1loA_gaincode_rev5 = 0x2086; ++ u16 clip1loA_gaincode_rev6 = 0x2086; ++ u16 clip1lo_gaincode; ++ u8 crsminG_th = 0x18; ++ u8 crsminG_th_rev5 = 0x18; ++ u8 crsminG_th_rev6 = 0x18; ++ u8 crsminA_th = 0x1e; ++ u8 crsminA_th_rev4 = 0x24; ++ u8 crsminA_th_rev5 = 0x24; ++ u8 crsminA_th_rev6 = 0x24; ++ u8 crsmin_th; ++ u8 crsminlG_th = 0x18; ++ u8 crsminlG_th_rev5 = 0x18; ++ u8 crsminlG_th_rev6 = 0x18; ++ u8 crsminlA_th = 0x1e; ++ u8 crsminlA_th_rev4 = 0x24; ++ u8 crsminlA_th_rev5 = 0x24; ++ u8 crsminlA_th_rev6 = 0x24; ++ u8 crsminl_th = 0; ++ u8 crsminuG_th = 0x18; ++ u8 crsminuG_th_rev5 = 0x18; ++ u8 crsminuG_th_rev6 = 0x18; ++ u8 crsminuA_th = 0x1e; ++ u8 crsminuA_th_rev4 = 0x24; ++ u8 crsminuA_th_rev5 = 0x24; ++ u8 crsminuA_th_rev6 = 0x24; ++ u8 crsminuA_th_rev6_224B0 = 0x2d; ++ u8 crsminu_th; ++ u16 nbclipG_th = 0x20d; ++ u16 nbclipG_th_rev4 = 0x1a1; ++ u16 nbclipG_th_rev5 = 0x1d0; ++ u16 nbclipG_th_rev6 = 0x1d0; ++ u16 nbclipA_th = 0x1a1; ++ u16 nbclipA_th_rev4 = 0x107; ++ u16 nbclipA_th_rev5 = 0x0a9; ++ u16 nbclipA_th_rev6 = 0x0f0; ++ u16 nbclip_th = 0; ++ u8 w1clipG_th = 5; ++ u8 w1clipG_th_rev5 = 9; ++ u8 w1clipG_th_rev6 = 5; ++ u8 w1clipA_th = 25, w1clip_th; ++ u8 rssi_gain_default = 0x50; ++ u8 rssiG_gain_rev6_224B0 = 0x50; ++ u8 rssiA_gain_rev5 = 0x90; ++ u8 rssiA_gain_rev6 = 0x90; ++ u8 rssi_gain; ++ u16 regval[21]; ++ u8 triso; ++ ++ triso = (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.triso : ++ pi->srom_fem2g.triso; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (pi->pubpi.radiorev == 5) { ++ wlc_phy_workarounds_nphy_gainctrl_2057_rev5(pi); ++ } else if (pi->pubpi.radiorev == 7) { ++ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); ++ ++ mod_phy_reg(pi, 0x283, (0xff << 0), (0x44 << 0)); ++ mod_phy_reg(pi, 0x280, (0xff << 0), (0x44 << 0)); ++ ++ } else if ((pi->pubpi.radiorev == 3) ++ || (pi->pubpi.radiorev == 8)) { ++ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); ++ ++ if (pi->pubpi.radiorev == 8) { ++ mod_phy_reg(pi, 0x283, ++ (0xff << 0), (0x44 << 0)); ++ mod_phy_reg(pi, 0x280, ++ (0xff << 0), (0x44 << 0)); ++ } ++ } else { ++ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); ++ } ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ mod_phy_reg(pi, 0xa0, (0x1 << 6), (1 << 6)); ++ ++ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); ++ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); ++ ++ currband = ++ read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; ++ if (currband == 0) { ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ if (pi->pubpi.radiorev == 11) { ++ lna1_gain_db = lna1G_gain_db_rev6_224B0; ++ lna2_gain_db = lna2G_gain_db_rev6_224B0; ++ rfseq_init_gain = ++ rfseqG_init_gain_rev6_224B0; ++ init_gaincode = ++ initG_gaincode_rev6_224B0; ++ clip1hi_gaincode = ++ clip1hiG_gaincode_rev6; ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6_224B0; ++ nbclip_th = nbclipG_th_rev6; ++ w1clip_th = w1clipG_th_rev6; ++ crsmin_th = crsminG_th_rev6; ++ crsminl_th = crsminlG_th_rev6; ++ crsminu_th = crsminuG_th_rev6; ++ rssi_gain = rssiG_gain_rev6_224B0; ++ } else { ++ lna1_gain_db = lna1G_gain_db_rev6; ++ lna2_gain_db = lna2G_gain_db_rev6; ++ if (pi->sh->boardflags & BFL_EXTLNA) { ++ ++ rfseq_init_gain = ++ rfseqG_init_gain_rev6_elna; ++ init_gaincode = ++ initG_gaincode_rev6_elna; ++ } else { ++ rfseq_init_gain = ++ rfseqG_init_gain_rev6; ++ init_gaincode = ++ initG_gaincode_rev6; ++ } ++ clip1hi_gaincode = ++ clip1hiG_gaincode_rev6; ++ switch (triso) { ++ case 0: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [0]; ++ break; ++ case 1: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [1]; ++ break; ++ case 2: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [2]; ++ break; ++ case 3: ++ default: ++ ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [3]; ++ break; ++ case 4: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [4]; ++ break; ++ case 5: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [5]; ++ break; ++ case 6: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [6]; ++ break; ++ case 7: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev6 ++ [7]; ++ break; ++ } ++ nbclip_th = nbclipG_th_rev6; ++ w1clip_th = w1clipG_th_rev6; ++ crsmin_th = crsminG_th_rev6; ++ crsminl_th = crsminlG_th_rev6; ++ crsminu_th = crsminuG_th_rev6; ++ rssi_gain = rssi_gain_default; ++ } ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { ++ lna1_gain_db = lna1G_gain_db_rev5; ++ lna2_gain_db = lna2G_gain_db_rev5; ++ if (pi->sh->boardflags & BFL_EXTLNA) { ++ ++ rfseq_init_gain = ++ rfseqG_init_gain_rev5_elna; ++ init_gaincode = ++ initG_gaincode_rev5_elna; ++ } else { ++ rfseq_init_gain = rfseqG_init_gain_rev5; ++ init_gaincode = initG_gaincode_rev5; ++ } ++ clip1hi_gaincode = clip1hiG_gaincode_rev5; ++ switch (triso) { ++ case 0: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[0]; ++ break; ++ case 1: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[1]; ++ break; ++ case 2: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[2]; ++ break; ++ case 3: ++ ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[3]; ++ break; ++ case 4: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[4]; ++ break; ++ case 5: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[5]; ++ break; ++ case 6: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[6]; ++ break; ++ case 7: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[7]; ++ break; ++ default: ++ clip1lo_gaincode = ++ clip1loG_gaincode_rev5[3]; ++ break; ++ } ++ nbclip_th = nbclipG_th_rev5; ++ w1clip_th = w1clipG_th_rev5; ++ crsmin_th = crsminG_th_rev5; ++ crsminl_th = crsminlG_th_rev5; ++ crsminu_th = crsminuG_th_rev5; ++ rssi_gain = rssi_gain_default; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { ++ lna1_gain_db = lna1G_gain_db_rev4; ++ lna2_gain_db = lna2G_gain_db; ++ rfseq_init_gain = rfseqG_init_gain_rev4; ++ init_gaincode = initG_gaincode_rev4; ++ clip1hi_gaincode = clip1hiG_gaincode_rev4; ++ clip1lo_gaincode = clip1loG_gaincode; ++ nbclip_th = nbclipG_th_rev4; ++ w1clip_th = w1clipG_th; ++ crsmin_th = crsminG_th; ++ crsminl_th = crsminlG_th; ++ crsminu_th = crsminuG_th; ++ rssi_gain = rssi_gain_default; ++ } else { ++ lna1_gain_db = lna1G_gain_db; ++ lna2_gain_db = lna2G_gain_db; ++ rfseq_init_gain = rfseqG_init_gain; ++ init_gaincode = initG_gaincode; ++ clip1hi_gaincode = clip1hiG_gaincode; ++ clip1lo_gaincode = clip1loG_gaincode; ++ nbclip_th = nbclipG_th; ++ w1clip_th = w1clipG_th; ++ crsmin_th = crsminG_th; ++ crsminl_th = crsminlG_th; ++ crsminu_th = crsminuG_th; ++ rssi_gain = rssi_gain_default; ++ } ++ tia_gain_db = tiaG_gain_db; ++ tia_gainbits = tiaG_gainbits; ++ clip1md_gaincode = clip1mdG_gaincode; ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ lna1_gain_db = lna1A_gain_db_rev6; ++ lna2_gain_db = lna2A_gain_db_rev6; ++ tia_gain_db = tiaA_gain_db_rev6; ++ tia_gainbits = tiaA_gainbits_rev6; ++ rfseq_init_gain = rfseqA_init_gain_rev6; ++ init_gaincode = initA_gaincode_rev6; ++ clip1hi_gaincode = clip1hiA_gaincode_rev6; ++ clip1md_gaincode = clip1mdA_gaincode_rev6; ++ clip1lo_gaincode = clip1loA_gaincode_rev6; ++ crsmin_th = crsminA_th_rev6; ++ crsminl_th = crsminlA_th_rev6; ++ if ((pi->pubpi.radiorev == 11) && ++ (CHSPEC_IS40(pi->radio_chanspec) == 0)) ++ crsminu_th = crsminuA_th_rev6_224B0; ++ else ++ crsminu_th = crsminuA_th_rev6; ++ ++ nbclip_th = nbclipA_th_rev6; ++ rssi_gain = rssiA_gain_rev6; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { ++ lna1_gain_db = lna1A_gain_db_rev5; ++ lna2_gain_db = lna2A_gain_db_rev5; ++ tia_gain_db = tiaA_gain_db_rev5; ++ tia_gainbits = tiaA_gainbits_rev5; ++ rfseq_init_gain = rfseqA_init_gain_rev5; ++ init_gaincode = initA_gaincode_rev5; ++ clip1hi_gaincode = clip1hiA_gaincode_rev5; ++ clip1md_gaincode = clip1mdA_gaincode_rev5; ++ clip1lo_gaincode = clip1loA_gaincode_rev5; ++ crsmin_th = crsminA_th_rev5; ++ crsminl_th = crsminlA_th_rev5; ++ crsminu_th = crsminuA_th_rev5; ++ nbclip_th = nbclipA_th_rev5; ++ rssi_gain = rssiA_gain_rev5; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { ++ lna1_gain_db = lna1A_gain_db_rev4; ++ lna2_gain_db = lna2A_gain_db_rev4; ++ tia_gain_db = tiaA_gain_db_rev4; ++ tia_gainbits = tiaA_gainbits_rev4; ++ if (pi->sh->boardflags & BFL_EXTLNA_5GHz) { ++ ++ rfseq_init_gain = ++ rfseqA_init_gain_rev4_elna; ++ init_gaincode = ++ initA_gaincode_rev4_elna; ++ } else { ++ rfseq_init_gain = rfseqA_init_gain_rev4; ++ init_gaincode = initA_gaincode_rev4; ++ } ++ clip1hi_gaincode = clip1hiA_gaincode_rev4; ++ clip1md_gaincode = clip1mdA_gaincode_rev4; ++ clip1lo_gaincode = clip1loA_gaincode_rev4; ++ crsmin_th = crsminA_th_rev4; ++ crsminl_th = crsminlA_th_rev4; ++ crsminu_th = crsminuA_th_rev4; ++ nbclip_th = nbclipA_th_rev4; ++ rssi_gain = rssi_gain_default; ++ } else { ++ lna1_gain_db = lna1A_gain_db; ++ lna2_gain_db = lna2A_gain_db; ++ tia_gain_db = tiaA_gain_db; ++ tia_gainbits = tiaA_gainbits; ++ rfseq_init_gain = rfseqA_init_gain; ++ init_gaincode = initA_gaincode; ++ clip1hi_gaincode = clip1hiA_gaincode; ++ clip1md_gaincode = clip1mdA_gaincode; ++ clip1lo_gaincode = clip1loA_gaincode; ++ crsmin_th = crsminA_th; ++ crsminl_th = crsminlA_th; ++ crsminu_th = crsminuA_th; ++ nbclip_th = nbclipA_th; ++ rssi_gain = rssi_gain_default; ++ } ++ w1clip_th = w1clipA_th; ++ } ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC | ++ RADIO_2056_RX0), 0x17); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC | ++ RADIO_2056_RX1), 0x17); ++ ++ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX0), ++ 0xf0); ++ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX1), ++ 0xf0); ++ ++ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX0), ++ 0x0); ++ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX1), ++ 0x0); ++ ++ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX0), ++ rssi_gain); ++ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX1), ++ rssi_gain); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC | ++ RADIO_2056_RX0), 0x17); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC | ++ RADIO_2056_RX1), 0x17); ++ ++ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX0), ++ 0xFF); ++ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX1), ++ 0xFF); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, ++ 8, lna1_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, ++ 8, lna1_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, ++ 8, lna2_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, ++ 8, lna2_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, ++ 8, tia_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, ++ 8, tia_gain_db); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, ++ 8, tia_gainbits); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, ++ 8, tia_gainbits); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 6, 0x40, ++ 8, &lpf_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 6, 0x40, ++ 8, &lpf_gain_db); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 6, 0x40, ++ 8, &lpf_gainbits); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 6, 0x40, ++ 8, &lpf_gainbits); ++ ++ write_phy_reg(pi, 0x20, init_gaincode); ++ write_phy_reg(pi, 0x2a7, init_gaincode); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ pi->pubpi.phy_corenum, 0x106, 16, ++ rfseq_init_gain); ++ ++ write_phy_reg(pi, 0x22, clip1hi_gaincode); ++ write_phy_reg(pi, 0x2a9, clip1hi_gaincode); ++ ++ write_phy_reg(pi, 0x24, clip1md_gaincode); ++ write_phy_reg(pi, 0x2ab, clip1md_gaincode); ++ ++ write_phy_reg(pi, 0x37, clip1lo_gaincode); ++ write_phy_reg(pi, 0x2ad, clip1lo_gaincode); ++ ++ mod_phy_reg(pi, 0x27d, (0xff << 0), (crsmin_th << 0)); ++ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0)); ++ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0)); ++ ++ write_phy_reg(pi, 0x2b, nbclip_th); ++ write_phy_reg(pi, 0x41, nbclip_th); ++ ++ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1clip_th << 0)); ++ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1clip_th << 0)); ++ ++ write_phy_reg(pi, 0x150, 0x809c); ++ ++ } else { ++ ++ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); ++ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); ++ ++ write_phy_reg(pi, 0x2b, 0x84); ++ write_phy_reg(pi, 0x41, 0x84); ++ ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ write_phy_reg(pi, 0x6b, 0x2b); ++ write_phy_reg(pi, 0x6c, 0x2b); ++ write_phy_reg(pi, 0x6d, 0x9); ++ write_phy_reg(pi, 0x6e, 0x9); ++ } ++ ++ w1th = NPHY_RSSICAL_W1_TARGET - 4; ++ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1th << 0)); ++ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1th << 0)); ++ ++ if (CHSPEC_IS20(pi->radio_chanspec)) { ++ mod_phy_reg(pi, 0x1c, (0x1f << 0), (0x1 << 0)); ++ mod_phy_reg(pi, 0x32, (0x1f << 0), (0x1 << 0)); ++ ++ mod_phy_reg(pi, 0x1d, (0x1f << 0), (0x1 << 0)); ++ mod_phy_reg(pi, 0x33, (0x1f << 0), (0x1 << 0)); ++ } ++ ++ write_phy_reg(pi, 0x150, 0x809c); ++ ++ if (pi->nphy_gain_boost) ++ if ((CHSPEC_IS2G(pi->radio_chanspec)) && ++ (CHSPEC_IS40(pi->radio_chanspec))) ++ hpf_code = 4; ++ else ++ hpf_code = 5; ++ else if (CHSPEC_IS40(pi->radio_chanspec)) ++ hpf_code = 6; ++ else ++ hpf_code = 7; ++ ++ mod_phy_reg(pi, 0x20, (0x1f << 7), (hpf_code << 7)); ++ mod_phy_reg(pi, 0x36, (0x1f << 7), (hpf_code << 7)); ++ ++ for (ctr = 0; ctr < 4; ctr++) ++ regval[ctr] = (hpf_code << 8) | 0x7c; ++ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval); ++ ++ wlc_phy_adjust_lnagaintbl_nphy(pi); ++ ++ if (pi->nphy_elna_gain_config) { ++ regval[0] = 0; ++ regval[1] = 1; ++ regval[2] = 1; ++ regval[3] = 1; ++ wlc_phy_table_write_nphy(pi, 2, 4, 8, 16, regval); ++ wlc_phy_table_write_nphy(pi, 3, 4, 8, 16, regval); ++ ++ for (ctr = 0; ctr < 4; ctr++) ++ regval[ctr] = (hpf_code << 8) | 0x74; ++ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval); ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 2)) { ++ for (ctr = 0; ctr < 21; ctr++) ++ regval[ctr] = 3 * ctr; ++ wlc_phy_table_write_nphy(pi, 0, 21, 32, 16, regval); ++ wlc_phy_table_write_nphy(pi, 1, 21, 32, 16, regval); ++ ++ for (ctr = 0; ctr < 21; ctr++) ++ regval[ctr] = (u16) ctr; ++ wlc_phy_table_write_nphy(pi, 2, 21, 32, 16, regval); ++ wlc_phy_table_write_nphy(pi, 3, 21, 32, 16, regval); ++ } ++ ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_UPDATEGAINU, ++ rfseq_updategainu_events, ++ rfseq_updategainu_dlys, ++ sizeof(rfseq_updategainu_events) / ++ sizeof(rfseq_updategainu_events[0])); ++ ++ mod_phy_reg(pi, 0x153, (0xff << 8), (90 << 8)); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ mod_phy_reg(pi, ++ (NPHY_TO_BPHY_OFF + BPHY_OPTIONAL_MODES), ++ 0x7f, 0x4); ++ } ++} ++ ++static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) ++{ ++ u8 rfseq_rx2tx_events[] = { ++ NPHY_RFSEQ_CMD_NOP, ++ NPHY_RFSEQ_CMD_RXG_FBW, ++ NPHY_RFSEQ_CMD_TR_SWITCH, ++ NPHY_RFSEQ_CMD_CLR_HIQ_DIS, ++ NPHY_RFSEQ_CMD_RXPD_TXPD, ++ NPHY_RFSEQ_CMD_TX_GAIN, ++ NPHY_RFSEQ_CMD_EXT_PA ++ }; ++ u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 }; ++ u8 rfseq_tx2rx_events[] = { ++ NPHY_RFSEQ_CMD_NOP, ++ NPHY_RFSEQ_CMD_EXT_PA, ++ NPHY_RFSEQ_CMD_TX_GAIN, ++ NPHY_RFSEQ_CMD_RXPD_TXPD, ++ NPHY_RFSEQ_CMD_TR_SWITCH, ++ NPHY_RFSEQ_CMD_RXG_FBW, ++ NPHY_RFSEQ_CMD_CLR_HIQ_DIS ++ }; ++ u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; ++ u8 rfseq_tx2rx_events_rev3[] = { ++ NPHY_REV3_RFSEQ_CMD_EXT_PA, ++ NPHY_REV3_RFSEQ_CMD_INT_PA_PU, ++ NPHY_REV3_RFSEQ_CMD_TX_GAIN, ++ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, ++ NPHY_REV3_RFSEQ_CMD_TR_SWITCH, ++ NPHY_REV3_RFSEQ_CMD_RXG_FBW, ++ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, ++ NPHY_REV3_RFSEQ_CMD_END ++ }; ++ u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; ++ u8 rfseq_rx2tx_events_rev3[] = { ++ NPHY_REV3_RFSEQ_CMD_NOP, ++ NPHY_REV3_RFSEQ_CMD_RXG_FBW, ++ NPHY_REV3_RFSEQ_CMD_TR_SWITCH, ++ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, ++ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, ++ NPHY_REV3_RFSEQ_CMD_TX_GAIN, ++ NPHY_REV3_RFSEQ_CMD_INT_PA_PU, ++ NPHY_REV3_RFSEQ_CMD_EXT_PA, ++ NPHY_REV3_RFSEQ_CMD_END ++ }; ++ u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; ++ ++ u8 rfseq_rx2tx_events_rev3_ipa[] = { ++ NPHY_REV3_RFSEQ_CMD_NOP, ++ NPHY_REV3_RFSEQ_CMD_RXG_FBW, ++ NPHY_REV3_RFSEQ_CMD_TR_SWITCH, ++ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, ++ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, ++ NPHY_REV3_RFSEQ_CMD_TX_GAIN, ++ NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS, ++ NPHY_REV3_RFSEQ_CMD_INT_PA_PU, ++ NPHY_REV3_RFSEQ_CMD_END ++ }; ++ u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; ++ u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; ++ ++ s16 alpha0, alpha1, alpha2; ++ s16 beta0, beta1, beta2; ++ u32 leg_data_weights, ht_data_weights, nss1_data_weights, ++ stbc_data_weights; ++ u8 chan_freq_range = 0; ++ u16 dac_control = 0x0002; ++ u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 }; ++ u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 }; ++ u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 }; ++ u16 aux_adc_vmid_rev3[] = { 0xa2, 0xb4, 0xb4, 0x89 }; ++ u16 *aux_adc_vmid; ++ u16 aux_adc_gain_rev7[] = { 0x02, 0x02, 0x02, 0x02 }; ++ u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 }; ++ u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 }; ++ u16 *aux_adc_gain; ++ u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; ++ u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; ++ s32 min_nvar_val = 0x18d; ++ s32 min_nvar_offset_6mbps = 20; ++ u8 pdetrange; ++ u8 triso; ++ u16 regval; ++ u16 afectrl_adc_ctrl1_rev7 = 0x20; ++ u16 afectrl_adc_ctrl2_rev7 = 0x0; ++ u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77; ++ u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77; ++ u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77; ++ u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; ++ u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; ++ u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; ++ u16 ipalvlshift_3p3_war_en = 0; ++ u16 rccal_bcap_val, rccal_scap_val; ++ u16 rccal_tx20_11b_bcap = 0; ++ u16 rccal_tx20_11b_scap = 0; ++ u16 rccal_tx20_11n_bcap = 0; ++ u16 rccal_tx20_11n_scap = 0; ++ u16 rccal_tx40_11n_bcap = 0; ++ u16 rccal_tx40_11n_scap = 0; ++ u16 rx2tx_lpf_rc_lut_tx20_11b = 0; ++ u16 rx2tx_lpf_rc_lut_tx20_11n = 0; ++ u16 rx2tx_lpf_rc_lut_tx40_11n = 0; ++ u16 tx_lpf_bw_ofdm_20mhz = 0; ++ u16 tx_lpf_bw_ofdm_40mhz = 0; ++ u16 tx_lpf_bw_11b = 0; ++ u16 ipa2g_mainbias, ipa2g_casconv, ipa2g_biasfilt; ++ u16 txgm_idac_bleed = 0; ++ bool rccal_ovrd = false; ++ u16 freq; ++ int coreNum; ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 0); ++ else ++ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 1); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ or_phy_reg(pi, 0xb1, NPHY_IQFlip_ADC1 | NPHY_IQFlip_ADC2); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7)) { ++ mod_phy_reg(pi, 0x221, (0x1 << 4), (1 << 4)); ++ ++ mod_phy_reg(pi, 0x160, (0x7f << 0), (32 << 0)); ++ mod_phy_reg(pi, 0x160, (0x7f << 8), (39 << 8)); ++ mod_phy_reg(pi, 0x161, (0x7f << 0), (46 << 0)); ++ mod_phy_reg(pi, 0x161, (0x7f << 8), (51 << 8)); ++ mod_phy_reg(pi, 0x162, (0x7f << 0), (55 << 0)); ++ mod_phy_reg(pi, 0x162, (0x7f << 8), (58 << 8)); ++ mod_phy_reg(pi, 0x163, (0x7f << 0), (60 << 0)); ++ mod_phy_reg(pi, 0x163, (0x7f << 8), (62 << 8)); ++ mod_phy_reg(pi, 0x164, (0x7f << 0), (62 << 0)); ++ mod_phy_reg(pi, 0x164, (0x7f << 8), (63 << 8)); ++ mod_phy_reg(pi, 0x165, (0x7f << 0), (63 << 0)); ++ mod_phy_reg(pi, 0x165, (0x7f << 8), (64 << 8)); ++ mod_phy_reg(pi, 0x166, (0x7f << 0), (64 << 0)); ++ mod_phy_reg(pi, 0x166, (0x7f << 8), (64 << 8)); ++ mod_phy_reg(pi, 0x167, (0x7f << 0), (64 << 0)); ++ mod_phy_reg(pi, 0x167, (0x7f << 8), (64 << 8)); ++ } ++ ++ if (NREV_LE(pi->pubpi.phy_rev, 8)) { ++ write_phy_reg(pi, 0x23f, 0x1b0); ++ write_phy_reg(pi, 0x240, 0x1b0); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 8)) ++ mod_phy_reg(pi, 0xbd, (0xff << 0), (114 << 0)); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16, ++ &dac_control); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16, ++ &dac_control); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 0, 32, &leg_data_weights); ++ leg_data_weights = leg_data_weights & 0xffffff; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 0, 32, &leg_data_weights); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ 2, 0x15e, 16, ++ rfseq_rx2tx_dacbufpu_rev7); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x16e, 16, ++ rfseq_rx2tx_dacbufpu_rev7); ++ ++ if (PHY_IPA(pi)) ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, ++ rfseq_rx2tx_events_rev3_ipa, ++ rfseq_rx2tx_dlys_rev3_ipa, ++ sizeof ++ (rfseq_rx2tx_events_rev3_ipa) / ++ sizeof ++ (rfseq_rx2tx_events_rev3_ipa ++ [0])); ++ ++ mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14)); ++ mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14)); ++ ++ tx_lpf_bw_ofdm_20mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x154); ++ tx_lpf_bw_ofdm_40mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x159); ++ tx_lpf_bw_11b = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x152); ++ ++ if (PHY_IPA(pi)) { ++ ++ if (((pi->pubpi.radiorev == 5) ++ && (CHSPEC_IS40(pi->radio_chanspec) == 1)) ++ || (pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ ++ rccal_bcap_val = ++ read_radio_reg( ++ pi, ++ RADIO_2057_RCCAL_BCAP_VAL); ++ rccal_scap_val = ++ read_radio_reg( ++ pi, ++ RADIO_2057_RCCAL_SCAP_VAL); ++ ++ rccal_tx20_11b_bcap = rccal_bcap_val; ++ rccal_tx20_11b_scap = rccal_scap_val; ++ ++ if ((pi->pubpi.radiorev == 5) && ++ (CHSPEC_IS40(pi->radio_chanspec) == 1)) { ++ ++ rccal_tx20_11n_bcap = rccal_bcap_val; ++ rccal_tx20_11n_scap = rccal_scap_val; ++ rccal_tx40_11n_bcap = 0xc; ++ rccal_tx40_11n_scap = 0xc; ++ ++ rccal_ovrd = true; ++ ++ } else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ ++ tx_lpf_bw_ofdm_20mhz = 4; ++ tx_lpf_bw_11b = 1; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ rccal_tx20_11n_bcap = 0xc; ++ rccal_tx20_11n_scap = 0xc; ++ rccal_tx40_11n_bcap = 0xa; ++ rccal_tx40_11n_scap = 0xa; ++ } else { ++ rccal_tx20_11n_bcap = 0x14; ++ rccal_tx20_11n_scap = 0x14; ++ rccal_tx40_11n_bcap = 0xf; ++ rccal_tx40_11n_scap = 0xf; ++ } ++ ++ rccal_ovrd = true; ++ } ++ } ++ ++ } else { ++ ++ if (pi->pubpi.radiorev == 5) { ++ ++ tx_lpf_bw_ofdm_20mhz = 1; ++ tx_lpf_bw_ofdm_40mhz = 3; ++ ++ rccal_bcap_val = ++ read_radio_reg( ++ pi, ++ RADIO_2057_RCCAL_BCAP_VAL); ++ rccal_scap_val = ++ read_radio_reg( ++ pi, ++ RADIO_2057_RCCAL_SCAP_VAL); ++ ++ rccal_tx20_11b_bcap = rccal_bcap_val; ++ rccal_tx20_11b_scap = rccal_scap_val; ++ ++ rccal_tx20_11n_bcap = 0x13; ++ rccal_tx20_11n_scap = 0x11; ++ rccal_tx40_11n_bcap = 0x13; ++ rccal_tx40_11n_scap = 0x11; ++ ++ rccal_ovrd = true; ++ } ++ } ++ ++ if (rccal_ovrd) { ++ ++ rx2tx_lpf_rc_lut_tx20_11b = ++ (rccal_tx20_11b_bcap << 8) | ++ (rccal_tx20_11b_scap << 3) | ++ tx_lpf_bw_11b; ++ rx2tx_lpf_rc_lut_tx20_11n = ++ (rccal_tx20_11n_bcap << 8) | ++ (rccal_tx20_11n_scap << 3) | ++ tx_lpf_bw_ofdm_20mhz; ++ rx2tx_lpf_rc_lut_tx40_11n = ++ (rccal_tx40_11n_bcap << 8) | ++ (rccal_tx40_11n_scap << 3) | ++ tx_lpf_bw_ofdm_40mhz; ++ ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x152 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx20_11b); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x153 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx20_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x154 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx20_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x155 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx40_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x156 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx40_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x157 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx40_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x158 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx40_11n); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_RFSEQ, ++ 1, ++ 0x159 + coreNum * 0x10, ++ 16, ++ &rx2tx_lpf_rc_lut_tx40_11n); ++ } ++ ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 4), ++ 1, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ } ++ ++ write_phy_reg(pi, 0x32f, 0x3); ++ ++ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), ++ 1, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ ++ if ((pi->pubpi.radiorev == 3) || (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) { ++ if ((pi->sh->sromrev >= 8) ++ && (pi->sh->boardflags2 & BFL2_IPALVLSHIFT_3P3)) ++ ipalvlshift_3p3_war_en = 1; ++ ++ if (ipalvlshift_3p3_war_en) { ++ write_radio_reg(pi, RADIO_2057_GPAIO_CONFIG, ++ 0x5); ++ write_radio_reg(pi, RADIO_2057_GPAIO_SEL1, ++ 0x30); ++ write_radio_reg(pi, RADIO_2057_GPAIO_SEL0, 0x0); ++ or_radio_reg(pi, ++ RADIO_2057_RXTXBIAS_CONFIG_CORE0, ++ 0x1); ++ or_radio_reg(pi, ++ RADIO_2057_RXTXBIAS_CONFIG_CORE1, ++ 0x1); ++ ++ ipa2g_mainbias = 0x1f; ++ ++ ipa2g_casconv = 0x6f; ++ ++ ipa2g_biasfilt = 0xaa; ++ } else { ++ ++ ipa2g_mainbias = 0x2b; ++ ++ ipa2g_casconv = 0x7f; ++ ++ ipa2g_biasfilt = 0xee; ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ coreNum, IPA2G_IMAIN, ++ ipa2g_mainbias); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ coreNum, IPA2G_CASCONV, ++ ipa2g_casconv); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ coreNum, ++ IPA2G_BIAS_FILTER, ++ ipa2g_biasfilt); ++ } ++ } ++ } ++ ++ if (PHY_IPA(pi)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((pi->pubpi.radiorev == 3) ++ || (pi->pubpi.radiorev == 4) ++ || (pi->pubpi.radiorev == 6)) ++ txgm_idac_bleed = 0x7f; ++ ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ if (txgm_idac_bleed != 0) ++ WRITE_RADIO_REG4( ++ pi, RADIO_2057, ++ CORE, coreNum, ++ TXGM_IDAC_BLEED, ++ txgm_idac_bleed); ++ } ++ ++ if (pi->pubpi.radiorev == 5) { ++ ++ for (coreNum = 0; coreNum <= 1; ++ coreNum++) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, coreNum, ++ IPA2G_CASCONV, ++ 0x13); ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, coreNum, ++ IPA2G_IMAIN, ++ 0x1f); ++ WRITE_RADIO_REG4( ++ pi, RADIO_2057, ++ CORE, coreNum, ++ IPA2G_BIAS_FILTER, ++ 0xee); ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, coreNum, ++ PAD2G_IDACS, ++ 0x8a); ++ WRITE_RADIO_REG4( ++ pi, RADIO_2057, ++ CORE, coreNum, ++ PAD_BIAS_FILTER_BWS, ++ 0x3e); ++ } ++ ++ } else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ ++ if (CHSPEC_IS40(pi->radio_chanspec) == ++ 0) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, 0, ++ IPA2G_IMAIN, ++ 0x14); ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, 1, ++ IPA2G_IMAIN, ++ 0x12); ++ } else { ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, 0, ++ IPA2G_IMAIN, ++ 0x16); ++ WRITE_RADIO_REG4(pi, RADIO_2057, ++ CORE, 1, ++ IPA2G_IMAIN, ++ 0x16); ++ } ++ } ++ ++ } else { ++ freq = CHAN5G_FREQ(CHSPEC_CHANNEL( ++ pi->radio_chanspec)); ++ if (((freq >= 5180) && (freq <= 5230)) ++ || ((freq >= 5745) && (freq <= 5805))) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ 0, IPA5G_BIAS_FILTER, ++ 0xff); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ 1, IPA5G_BIAS_FILTER, ++ 0xff); ++ } ++ } ++ } else { ++ ++ if (pi->pubpi.radiorev != 5) { ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ coreNum, ++ TXMIX2G_TUNE_BOOST_PU, ++ 0x61); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, ++ coreNum, ++ TXGM_IDAC_BLEED, 0x70); ++ } ++ } ++ } ++ ++ if (pi->pubpi.radiorev == 4) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, ++ 0x05, 16, ++ &afectrl_adc_ctrl1_rev7); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, ++ 0x15, 16, ++ &afectrl_adc_ctrl1_rev7); ++ ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, ++ AFE_VCM_CAL_MASTER, 0x0); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, ++ AFE_SET_VCM_I, 0x3f); ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, ++ AFE_SET_VCM_Q, 0x3f); ++ } ++ } else { ++ mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2)); ++ ++ mod_phy_reg(pi, 0xa6, (0x1 << 0), 0); ++ mod_phy_reg(pi, 0x8f, (0x1 << 0), (0x1 << 0)); ++ mod_phy_reg(pi, 0xa7, (0x1 << 0), 0); ++ mod_phy_reg(pi, 0xa5, (0x1 << 0), (0x1 << 0)); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, ++ 0x05, 16, ++ &afectrl_adc_ctrl2_rev7); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, ++ 0x15, 16, ++ &afectrl_adc_ctrl2_rev7); ++ ++ mod_phy_reg(pi, 0xa6, (0x1 << 2), 0); ++ mod_phy_reg(pi, 0x8f, (0x1 << 2), 0); ++ mod_phy_reg(pi, 0xa7, (0x1 << 2), 0); ++ mod_phy_reg(pi, 0xa5, (0x1 << 2), 0); ++ } ++ ++ write_phy_reg(pi, 0x6a, 0x2); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 256, 32, ++ &min_nvar_offset_6mbps); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x138, 16, ++ &rfseq_pktgn_lpf_hpc_rev7); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x141, 16, ++ &rfseq_pktgn_lpf_h_hpc_rev7); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 3, 0x133, 16, ++ &rfseq_htpktgn_lpf_hpc_rev7); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x146, 16, ++ &rfseq_cckpktgn_lpf_hpc_rev7); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x123, 16, ++ &rfseq_tx2rx_lpf_h_hpc_rev7); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x12A, 16, ++ &rfseq_rx2tx_lpf_h_hpc_rev7); ++ ++ if (CHSPEC_IS40(pi->radio_chanspec) == 0) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, ++ 32, &min_nvar_val); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ 127, 32, &min_nvar_val); ++ } else { ++ min_nvar_val = noise_var_tbl_rev7[3]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, ++ 32, &min_nvar_val); ++ ++ min_nvar_val = noise_var_tbl_rev7[127]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ 127, 32, &min_nvar_val); ++ } ++ ++ wlc_phy_workarounds_nphy_gainctrl(pi); ++ ++ pdetrange = ++ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. ++ pdetrange : pi->srom_fem2g.pdetrange; ++ ++ if (pdetrange == 0) { ++ chan_freq_range = ++ wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ aux_adc_vmid_rev7_core0[3] = 0x70; ++ aux_adc_vmid_rev7_core1[3] = 0x70; ++ aux_adc_gain_rev7[3] = 2; ++ } else { ++ aux_adc_vmid_rev7_core0[3] = 0x80; ++ aux_adc_vmid_rev7_core1[3] = 0x80; ++ aux_adc_gain_rev7[3] = 3; ++ } ++ } else if (pdetrange == 1) { ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ aux_adc_vmid_rev7_core0[3] = 0x7c; ++ aux_adc_vmid_rev7_core1[3] = 0x7c; ++ aux_adc_gain_rev7[3] = 2; ++ } else { ++ aux_adc_vmid_rev7_core0[3] = 0x8c; ++ aux_adc_vmid_rev7_core1[3] = 0x8c; ++ aux_adc_gain_rev7[3] = 1; ++ } ++ } else if (pdetrange == 2) { ++ if (pi->pubpi.radioid == BCM2057_ID) { ++ if ((pi->pubpi.radiorev == 5) ++ || (pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ if (chan_freq_range == ++ WL_CHAN_FREQ_RANGE_2G) { ++ aux_adc_vmid_rev7_core0[3] = ++ 0x8c; ++ aux_adc_vmid_rev7_core1[3] = ++ 0x8c; ++ aux_adc_gain_rev7[3] = 0; ++ } else { ++ aux_adc_vmid_rev7_core0[3] = ++ 0x96; ++ aux_adc_vmid_rev7_core1[3] = ++ 0x96; ++ aux_adc_gain_rev7[3] = 0; ++ } ++ } ++ } ++ ++ } else if (pdetrange == 3) { ++ if (chan_freq_range == WL_CHAN_FREQ_RANGE_2G) { ++ aux_adc_vmid_rev7_core0[3] = 0x89; ++ aux_adc_vmid_rev7_core1[3] = 0x89; ++ aux_adc_gain_rev7[3] = 0; ++ } ++ ++ } else if (pdetrange == 5) { ++ ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ aux_adc_vmid_rev7_core0[3] = 0x80; ++ aux_adc_vmid_rev7_core1[3] = 0x80; ++ aux_adc_gain_rev7[3] = 3; ++ } else { ++ aux_adc_vmid_rev7_core0[3] = 0x70; ++ aux_adc_vmid_rev7_core1[3] = 0x70; ++ aux_adc_gain_rev7[3] = 2; ++ } ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x08, 16, ++ &aux_adc_vmid_rev7_core0); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x18, 16, ++ &aux_adc_vmid_rev7_core1); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x0c, 16, ++ &aux_adc_gain_rev7); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x1c, 16, ++ &aux_adc_gain_rev7); ++ ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ write_phy_reg(pi, 0x23f, 0x1f8); ++ write_phy_reg(pi, 0x240, 0x1f8); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 0, 32, &leg_data_weights); ++ leg_data_weights = leg_data_weights & 0xffffff; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 0, 32, &leg_data_weights); ++ ++ alpha0 = 293; ++ alpha1 = 435; ++ alpha2 = 261; ++ beta0 = 366; ++ beta1 = 205; ++ beta2 = 32; ++ write_phy_reg(pi, 0x145, alpha0); ++ write_phy_reg(pi, 0x146, alpha1); ++ write_phy_reg(pi, 0x147, alpha2); ++ write_phy_reg(pi, 0x148, beta0); ++ write_phy_reg(pi, 0x149, beta1); ++ write_phy_reg(pi, 0x14a, beta2); ++ ++ write_phy_reg(pi, 0x38, 0xC); ++ write_phy_reg(pi, 0x2ae, 0xC); ++ ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, ++ rfseq_tx2rx_events_rev3, ++ rfseq_tx2rx_dlys_rev3, ++ sizeof(rfseq_tx2rx_events_rev3) / ++ sizeof(rfseq_tx2rx_events_rev3[0])); ++ ++ if (PHY_IPA(pi)) ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, ++ rfseq_rx2tx_events_rev3_ipa, ++ rfseq_rx2tx_dlys_rev3_ipa, ++ sizeof ++ (rfseq_rx2tx_events_rev3_ipa) / ++ sizeof ++ (rfseq_rx2tx_events_rev3_ipa ++ [0])); ++ ++ if ((pi->sh->hw_phyrxchain != 0x3) && ++ (pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) { ++ ++ if (PHY_IPA(pi)) { ++ rfseq_rx2tx_dlys_rev3[5] = 59; ++ rfseq_rx2tx_dlys_rev3[6] = 1; ++ rfseq_rx2tx_events_rev3[7] = ++ NPHY_REV3_RFSEQ_CMD_END; ++ } ++ ++ wlc_phy_set_rfseq_nphy( ++ pi, NPHY_RFSEQ_RX2TX, ++ rfseq_rx2tx_events_rev3, ++ rfseq_rx2tx_dlys_rev3, ++ sizeof(rfseq_rx2tx_events_rev3) / ++ sizeof(rfseq_rx2tx_events_rev3[0])); ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ write_phy_reg(pi, 0x6a, 0x2); ++ else ++ write_phy_reg(pi, 0x6a, 0x9c40); ++ ++ mod_phy_reg(pi, 0x294, (0xf << 8), (7 << 8)); ++ ++ if (CHSPEC_IS40(pi->radio_chanspec) == 0) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, ++ 32, &min_nvar_val); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ 127, 32, &min_nvar_val); ++ } else { ++ min_nvar_val = noise_var_tbl_rev3[3]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, ++ 32, &min_nvar_val); ++ ++ min_nvar_val = noise_var_tbl_rev3[127]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ 127, 32, &min_nvar_val); ++ } ++ ++ wlc_phy_workarounds_nphy_gainctrl(pi); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16, ++ &dac_control); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16, ++ &dac_control); ++ ++ pdetrange = ++ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. ++ pdetrange : pi->srom_fem2g.pdetrange; ++ ++ if (pdetrange == 0) { ++ if (NREV_GE(pi->pubpi.phy_rev, 4)) { ++ aux_adc_vmid = aux_adc_vmid_rev4; ++ aux_adc_gain = aux_adc_gain_rev4; ++ } else { ++ aux_adc_vmid = aux_adc_vmid_rev3; ++ aux_adc_gain = aux_adc_gain_rev3; ++ } ++ chan_freq_range = ++ wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ switch (chan_freq_range) { ++ case WL_CHAN_FREQ_RANGE_5GL: ++ aux_adc_vmid[3] = 0x89; ++ aux_adc_gain[3] = 0; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GM: ++ aux_adc_vmid[3] = 0x89; ++ aux_adc_gain[3] = 0; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GH: ++ aux_adc_vmid[3] = 0x89; ++ aux_adc_gain[3] = 0; ++ break; ++ default: ++ break; ++ } ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x08, 16, aux_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x18, 16, aux_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x0c, 16, aux_adc_gain); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x1c, 16, aux_adc_gain); ++ } else if (pdetrange == 1) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x08, 16, sk_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x18, 16, sk_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x0c, 16, sk_adc_gain); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x1c, 16, sk_adc_gain); ++ } else if (pdetrange == 2) { ++ ++ u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x74 }; ++ u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x04 }; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ chan_freq_range = ++ wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ bcm_adc_vmid[3] = 0x8e; ++ bcm_adc_gain[3] = 0x03; ++ } else { ++ bcm_adc_vmid[3] = 0x94; ++ bcm_adc_gain[3] = 0x03; ++ } ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { ++ bcm_adc_vmid[3] = 0x84; ++ bcm_adc_gain[3] = 0x02; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x08, 16, bcm_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x18, 16, bcm_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x0c, 16, bcm_adc_gain); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x1c, 16, bcm_adc_gain); ++ } else if (pdetrange == 3) { ++ chan_freq_range = ++ wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ if ((NREV_GE(pi->pubpi.phy_rev, 4)) ++ && (chan_freq_range == WL_CHAN_FREQ_RANGE_2G)) { ++ ++ u16 auxadc_vmid[] = { ++ 0xa2, 0xb4, 0xb4, 0x270 ++ }; ++ u16 auxadc_gain[] = { ++ 0x02, 0x02, 0x02, 0x00 ++ }; ++ ++ wlc_phy_table_write_nphy(pi, ++ NPHY_TBL_ID_AFECTRL, 4, ++ 0x08, 16, auxadc_vmid); ++ wlc_phy_table_write_nphy(pi, ++ NPHY_TBL_ID_AFECTRL, 4, ++ 0x18, 16, auxadc_vmid); ++ wlc_phy_table_write_nphy(pi, ++ NPHY_TBL_ID_AFECTRL, 4, ++ 0x0c, 16, auxadc_gain); ++ wlc_phy_table_write_nphy(pi, ++ NPHY_TBL_ID_AFECTRL, 4, ++ 0x1c, 16, auxadc_gain); ++ } ++ } else if ((pdetrange == 4) || (pdetrange == 5)) { ++ u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x0 }; ++ u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x0 }; ++ u16 Vmid[2], Av[2]; ++ ++ chan_freq_range = ++ wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { ++ Vmid[0] = (pdetrange == 4) ? 0x8e : 0x89; ++ Vmid[1] = (pdetrange == 4) ? 0x96 : 0x89; ++ Av[0] = (pdetrange == 4) ? 2 : 0; ++ Av[1] = (pdetrange == 4) ? 2 : 0; ++ } else { ++ Vmid[0] = (pdetrange == 4) ? 0x89 : 0x74; ++ Vmid[1] = (pdetrange == 4) ? 0x8b : 0x70; ++ Av[0] = (pdetrange == 4) ? 2 : 0; ++ Av[1] = (pdetrange == 4) ? 2 : 0; ++ } ++ ++ bcm_adc_vmid[3] = Vmid[0]; ++ bcm_adc_gain[3] = Av[0]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x08, 16, bcm_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x0c, 16, bcm_adc_gain); ++ ++ bcm_adc_vmid[3] = Vmid[1]; ++ bcm_adc_gain[3] = Av[1]; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x18, 16, bcm_adc_vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, ++ 0x1c, 16, bcm_adc_gain); ++ } ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX0), ++ 0x0); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX1), ++ 0x0); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX0), ++ 0x6); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX1), ++ 0x6); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX0), ++ 0x7); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX1), ++ 0x7); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX0), ++ 0x88); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX1), ++ 0x88); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX0), ++ 0x0); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX1), ++ 0x0); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX0), ++ 0x0); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX1), ++ 0x0); ++ ++ triso = ++ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. ++ triso : pi->srom_fem2g.triso; ++ if (triso == 7) { ++ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0); ++ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1); ++ } ++ ++ wlc_phy_war_txchain_upd_nphy(pi, pi->sh->hw_phytxchain); ++ ++ if (((pi->sh->boardflags2 & BFL2_APLL_WAR) && ++ (CHSPEC_IS5G(pi->radio_chanspec))) || ++ (((pi->sh->boardflags2 & BFL2_GPLL_WAR) || ++ (pi->sh->boardflags2 & BFL2_GPLL_WAR2)) && ++ (CHSPEC_IS2G(pi->radio_chanspec)))) { ++ nss1_data_weights = 0x00088888; ++ ht_data_weights = 0x00088888; ++ stbc_data_weights = 0x00088888; ++ } else { ++ nss1_data_weights = 0x88888888; ++ ht_data_weights = 0x88888888; ++ stbc_data_weights = 0x88888888; ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 1, 32, &nss1_data_weights); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 2, 32, &ht_data_weights); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, ++ 1, 3, 32, &stbc_data_weights); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 4)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ write_radio_reg(pi, ++ RADIO_2056_TX_GMBB_IDAC | ++ RADIO_2056_TX0, 0x70); ++ write_radio_reg(pi, ++ RADIO_2056_TX_GMBB_IDAC | ++ RADIO_2056_TX1, 0x70); ++ } ++ } ++ ++ if (!pi->edcrs_threshold_lock) { ++ write_phy_reg(pi, 0x224, 0x3eb); ++ write_phy_reg(pi, 0x225, 0x3eb); ++ write_phy_reg(pi, 0x226, 0x341); ++ write_phy_reg(pi, 0x227, 0x341); ++ write_phy_reg(pi, 0x228, 0x42b); ++ write_phy_reg(pi, 0x229, 0x42b); ++ write_phy_reg(pi, 0x22a, 0x381); ++ write_phy_reg(pi, 0x22b, 0x381); ++ write_phy_reg(pi, 0x22c, 0x42b); ++ write_phy_reg(pi, 0x22d, 0x42b); ++ write_phy_reg(pi, 0x22e, 0x381); ++ write_phy_reg(pi, 0x22f, 0x381); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ ++ if (pi->sh->boardflags2 & BFL2_SINGLEANT_CCK) ++ wlapi_bmac_mhf(pi->sh->physhim, MHF4, ++ MHF4_BPHY_TXCORE0, ++ MHF4_BPHY_TXCORE0, BRCM_BAND_ALL); ++ } ++ } else { ++ ++ if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD || ++ (pi->sh->boardtype == 0x8b)) { ++ uint i; ++ u8 war_dlys[] = { 1, 6, 6, 2, 4, 20, 1 }; ++ for (i = 0; i < ARRAY_SIZE(rfseq_rx2tx_dlys); i++) ++ rfseq_rx2tx_dlys[i] = war_dlys[i]; ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec) && pi->phy_5g_pwrgain) { ++ and_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0xf7); ++ and_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0xf7); ++ } else { ++ or_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0x8); ++ or_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0x8); ++ } ++ ++ regval = 0x000a; ++ wlc_phy_table_write_nphy(pi, 8, 1, 0, 16, ®val); ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x10, 16, ®val); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) { ++ regval = 0xcdaa; ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x02, 16, ®val); ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x12, 16, ®val); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ regval = 0x0000; ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x08, 16, ®val); ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x18, 16, ®val); ++ ++ regval = 0x7aab; ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x07, 16, ®val); ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x17, 16, ®val); ++ ++ regval = 0x0800; ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x06, 16, ®val); ++ wlc_phy_table_write_nphy(pi, 8, 1, 0x16, 16, ®val); ++ } ++ ++ write_phy_reg(pi, 0xf8, 0x02d8); ++ write_phy_reg(pi, 0xf9, 0x0301); ++ write_phy_reg(pi, 0xfa, 0x02d8); ++ write_phy_reg(pi, 0xfb, 0x0301); ++ ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events, ++ rfseq_rx2tx_dlys, ++ sizeof(rfseq_rx2tx_events) / ++ sizeof(rfseq_rx2tx_events[0])); ++ ++ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events, ++ rfseq_tx2rx_dlys, ++ sizeof(rfseq_tx2rx_events) / ++ sizeof(rfseq_tx2rx_events[0])); ++ ++ wlc_phy_workarounds_nphy_gainctrl(pi); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ ++ if (read_phy_reg(pi, 0xa0) & NPHY_MLenable) ++ wlapi_bmac_mhf(pi->sh->physhim, MHF3, ++ MHF3_NPHY_MLADV_WAR, ++ MHF3_NPHY_MLADV_WAR, ++ BRCM_BAND_ALL); ++ ++ } else if (NREV_IS(pi->pubpi.phy_rev, 2)) { ++ write_phy_reg(pi, 0x1e3, 0x0); ++ write_phy_reg(pi, 0x1e4, 0x0); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0x90, (0x1 << 7), 0); ++ ++ alpha0 = 293; ++ alpha1 = 435; ++ alpha2 = 261; ++ beta0 = 366; ++ beta1 = 205; ++ beta2 = 32; ++ write_phy_reg(pi, 0x145, alpha0); ++ write_phy_reg(pi, 0x146, alpha1); ++ write_phy_reg(pi, 0x147, alpha2); ++ write_phy_reg(pi, 0x148, beta0); ++ write_phy_reg(pi, 0x149, beta1); ++ write_phy_reg(pi, 0x14a, beta2); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) { ++ mod_phy_reg(pi, 0x142, (0xf << 12), 0); ++ ++ write_phy_reg(pi, 0x192, 0xb5); ++ write_phy_reg(pi, 0x193, 0xa4); ++ write_phy_reg(pi, 0x194, 0x0); ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0x221, ++ NPHY_FORCESIG_DECODEGATEDCLKS, ++ NPHY_FORCESIG_DECODEGATEDCLKS); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi) ++{ ++ int j, type = 2; ++ u16 addr_offset = 0x2c5; ++ ++ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) ++ write_phy_reg(pi, addr_offset + j, ++ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]); ++} ++ ++static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals) ++{ ++ ++ if (write == 0) { ++ vals[0] = read_phy_reg(pi, 0x2c); ++ vals[1] = read_phy_reg(pi, 0x42); ++ } else { ++ write_phy_reg(pi, 0x2c, vals[0]); ++ write_phy_reg(pi, 0x42, vals[1]); ++ } ++} ++ ++static void wlc_phy_ipa_internal_tssi_setup_nphy(struct brcms_phy *pi) ++{ ++ u8 core; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER, 0x5); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MUX, 0xe); ++ ++ if (pi->pubpi.radiorev != 5) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TSSIA, 0); ++ ++ if (!NREV_IS(pi->pubpi.phy_rev, 7)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TSSIG, 0x1); ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TSSIG, 0x31); ++ } else { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER, 0x9); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MUX, 0xc); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSIG, 0); ++ ++ if (pi->pubpi.radiorev != 5) { ++ if (!NREV_IS(pi->pubpi.phy_rev, 7)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIA, 0x1); ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIA, 0x31); ++ } ++ } ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG, ++ 0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC, ++ 0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM, ++ 0x3); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1, ++ 0x0); ++ } ++ } else { ++ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR31, ++ (CHSPEC_IS2G(pi->radio_chanspec)) ? 0x128 : ++ 0x80); ++ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR30, 0x0); ++ WRITE_RADIO_SYN(pi, RADIO_2056, GPIO_MASTER1, 0x29); ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_VCM_HG, ++ 0x0); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_IDAC, ++ 0x0); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_VCM, ++ 0x3); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TX_AMP_DET, ++ 0x0); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC1, ++ 0x8); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC2, ++ 0x0); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC3, ++ 0x0); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TX_SSI_MASTER, 0x5); ++ ++ if (pi->pubpi.radiorev != 5) ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, ++ core, TSSIA, 0x0); ++ if (NREV_GE(pi->pubpi.phy_rev, 5)) ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, ++ core, TSSIG, 0x31); ++ else ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, ++ core, TSSIG, 0x11); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TX_SSI_MUX, 0xe); ++ } else { ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TX_SSI_MASTER, 0x9); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TSSIA, 0x31); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TSSIG, 0x0); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TX_SSI_MUX, 0xc); ++ } ++ } ++ } ++} ++ ++static void ++wlc_phy_rfctrl_override_nphy(struct brcms_phy *pi, u16 field, u16 value, ++ u8 core_mask, u8 off) ++{ ++ u8 core_num; ++ u16 addr = 0, mask = 0, en_addr = 0, val_addr = 0, en_mask = ++ 0, val_mask = 0; ++ u8 shift = 0, val_shift = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ ++ en_mask = field; ++ for (core_num = 0; core_num < 2; core_num++) { ++ ++ switch (field) { ++ case (0x1 << 1): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 2): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 1); ++ val_shift = 1; ++ break; ++ case (0x1 << 3): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 2); ++ val_shift = 2; ++ break; ++ case (0x1 << 4): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 4); ++ val_shift = 4; ++ break; ++ case (0x1 << 5): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 5); ++ val_shift = 5; ++ break; ++ case (0x1 << 6): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 6); ++ val_shift = 6; ++ break; ++ case (0x1 << 7): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x1 << 7); ++ val_shift = 7; ++ break; ++ case (0x1 << 8): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x7 << 8); ++ val_shift = 8; ++ break; ++ case (0x1 << 11): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7a : 0x7d; ++ val_mask = (0x7 << 13); ++ val_shift = 13; ++ break; ++ ++ case (0x1 << 9): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0xf8 : 0xfa; ++ val_mask = (0x7 << 0); ++ val_shift = 0; ++ break; ++ ++ case (0x1 << 10): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0xf8 : 0xfa; ++ val_mask = (0x7 << 4); ++ val_shift = 4; ++ break; ++ ++ case (0x1 << 12): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7b : 0x7e; ++ val_mask = (0xffff << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 13): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0x7c : 0x7f; ++ val_mask = (0xffff << 0); ++ val_shift = 0; ++ break; ++ case (0x1 << 14): ++ en_addr = (core_num == 0) ? 0xe7 : 0xec; ++ val_addr = (core_num == 0) ? 0xf9 : 0xfb; ++ val_mask = (0x3 << 6); ++ val_shift = 6; ++ break; ++ case (0x1 << 0): ++ en_addr = (core_num == 0) ? 0xe5 : 0xe6; ++ val_addr = (core_num == 0) ? 0xf9 : 0xfb; ++ val_mask = (0x1 << 15); ++ val_shift = 15; ++ break; ++ default: ++ addr = 0xffff; ++ break; ++ } ++ ++ if (off) { ++ and_phy_reg(pi, en_addr, ~en_mask); ++ and_phy_reg(pi, val_addr, ~val_mask); ++ } else { ++ ++ if ((core_mask == 0) ++ || (core_mask & (1 << core_num))) { ++ or_phy_reg(pi, en_addr, en_mask); ++ ++ if (addr != 0xffff) ++ mod_phy_reg(pi, val_addr, ++ val_mask, ++ (value << ++ val_shift)); ++ } ++ } ++ } ++ } else { ++ ++ if (off) { ++ and_phy_reg(pi, 0xec, ~field); ++ value = 0x0; ++ } else { ++ or_phy_reg(pi, 0xec, field); ++ } ++ ++ for (core_num = 0; core_num < 2; core_num++) { ++ ++ switch (field) { ++ case (0x1 << 1): ++ case (0x1 << 9): ++ case (0x1 << 12): ++ case (0x1 << 13): ++ case (0x1 << 14): ++ addr = 0x78; ++ ++ core_mask = 0x1; ++ break; ++ case (0x1 << 2): ++ case (0x1 << 3): ++ case (0x1 << 4): ++ case (0x1 << 5): ++ case (0x1 << 6): ++ case (0x1 << 7): ++ case (0x1 << 8): ++ addr = (core_num == 0) ? 0x7a : 0x7d; ++ break; ++ case (0x1 << 10): ++ addr = (core_num == 0) ? 0x7b : 0x7e; ++ break; ++ case (0x1 << 11): ++ addr = (core_num == 0) ? 0x7c : 0x7f; ++ break; ++ default: ++ addr = 0xffff; ++ } ++ ++ switch (field) { ++ case (0x1 << 1): ++ mask = (0x7 << 3); ++ shift = 3; ++ break; ++ case (0x1 << 9): ++ mask = (0x1 << 2); ++ shift = 2; ++ break; ++ case (0x1 << 12): ++ mask = (0x1 << 8); ++ shift = 8; ++ break; ++ case (0x1 << 13): ++ mask = (0x1 << 9); ++ shift = 9; ++ break; ++ case (0x1 << 14): ++ mask = (0xf << 12); ++ shift = 12; ++ break; ++ case (0x1 << 2): ++ mask = (0x1 << 0); ++ shift = 0; ++ break; ++ case (0x1 << 3): ++ mask = (0x1 << 1); ++ shift = 1; ++ break; ++ case (0x1 << 4): ++ mask = (0x1 << 2); ++ shift = 2; ++ break; ++ case (0x1 << 5): ++ mask = (0x3 << 4); ++ shift = 4; ++ break; ++ case (0x1 << 6): ++ mask = (0x3 << 6); ++ shift = 6; ++ break; ++ case (0x1 << 7): ++ mask = (0x1 << 8); ++ shift = 8; ++ break; ++ case (0x1 << 8): ++ mask = (0x1 << 9); ++ shift = 9; ++ break; ++ case (0x1 << 10): ++ mask = 0x1fff; ++ shift = 0x0; ++ break; ++ case (0x1 << 11): ++ mask = 0x1fff; ++ shift = 0x0; ++ break; ++ default: ++ mask = 0x0; ++ shift = 0x0; ++ break; ++ } ++ ++ if ((addr != 0xffff) && (core_mask & (1 << core_num))) ++ mod_phy_reg(pi, addr, mask, (value << shift)); ++ } ++ ++ or_phy_reg(pi, 0xec, (0x1 << 0)); ++ or_phy_reg(pi, 0x78, (0x1 << 0)); ++ udelay(1); ++ and_phy_reg(pi, 0xec, ~(0x1 << 0)); ++ } ++} ++ ++static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi) ++{ ++ s32 rssi_buf[4]; ++ s32 int_val; ++ ++ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) || PHY_MUTED(pi)) ++ ++ return; ++ ++ if (PHY_IPA(pi)) ++ wlc_phy_ipa_internal_tssi_setup_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), ++ 0, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ else if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 0); ++ ++ wlc_phy_stopplayback_nphy(pi); ++ ++ wlc_phy_tx_tone_nphy(pi, 4000, 0, 0, 0, false); ++ ++ udelay(20); ++ int_val = ++ wlc_phy_poll_rssi_nphy(pi, (u8) NPHY_RSSI_SEL_TSSI_2G, rssi_buf, ++ 1); ++ wlc_phy_stopplayback_nphy(pi); ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), ++ 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ else if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 1); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g = ++ (u8) ((int_val >> 24) & 0xff); ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g = ++ (u8) ((int_val >> 24) & 0xff); ++ ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g = ++ (u8) ((int_val >> 8) & 0xff); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g = ++ (u8) ((int_val >> 8) & 0xff); ++ } else { ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g = ++ (u8) ((int_val >> 24) & 0xff); ++ ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g = ++ (u8) ((int_val >> 8) & 0xff); ++ ++ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g = ++ (u8) ((int_val >> 16) & 0xff); ++ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g = ++ (u8) ((int_val) & 0xff); ++ } ++ ++} ++ ++static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi) ++{ ++ u8 idx, idx2, i, delta_ind; ++ ++ for (idx = TXP_FIRST_CCK; idx <= TXP_LAST_CCK; idx++) ++ pi->adj_pwr_tbl_nphy[idx] = pi->tx_power_offset[idx]; ++ ++ for (i = 0; i < 4; i++) { ++ idx2 = 0; ++ ++ delta_ind = 0; ++ ++ switch (i) { ++ case 0: ++ ++ if (CHSPEC_IS40(pi->radio_chanspec) ++ && NPHY_IS_SROM_REINTERPRET) { ++ idx = TXP_FIRST_MCS_40_SISO; ++ } else { ++ idx = (CHSPEC_IS40(pi->radio_chanspec)) ? ++ TXP_FIRST_OFDM_40_SISO : TXP_FIRST_OFDM; ++ delta_ind = 1; ++ } ++ break; ++ ++ case 1: ++ ++ idx = (CHSPEC_IS40(pi->radio_chanspec)) ? ++ TXP_FIRST_MCS_40_CDD : TXP_FIRST_MCS_20_CDD; ++ break; ++ ++ case 2: ++ ++ idx = (CHSPEC_IS40(pi->radio_chanspec)) ? ++ TXP_FIRST_MCS_40_STBC : TXP_FIRST_MCS_20_STBC; ++ break; ++ ++ case 3: ++ ++ idx = (CHSPEC_IS40(pi->radio_chanspec)) ? ++ TXP_FIRST_MCS_40_SDM : TXP_FIRST_MCS_20_SDM; ++ break; ++ } ++ ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ idx = idx + delta_ind; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx++]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ idx = idx + 1 - delta_ind; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = ++ pi->tx_power_offset[idx]; ++ } ++} ++ ++static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) ++{ ++ u32 idx; ++ s16 a1[2], b0[2], b1[2]; ++ s8 target_pwr_qtrdbm[2]; ++ s32 num, den, pwr_est; ++ u8 chan_freq_range; ++ u8 idle_tssi[2]; ++ u32 tbl_id, tbl_len, tbl_offset; ++ u32 regval[64]; ++ u8 core; ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); ++ (void)R_REG(&pi->regs->maccontrol); ++ udelay(1); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ or_phy_reg(pi, 0x122, (0x1 << 0)); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15))); ++ else ++ or_phy_reg(pi, 0x1e7, (0x1 << 15)); ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); ++ ++ if (pi->sh->sromrev < 4) { ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; ++ target_pwr_qtrdbm[0] = 13 * 4; ++ target_pwr_qtrdbm[1] = 13 * 4; ++ a1[0] = -424; ++ a1[1] = -424; ++ b0[0] = 5612; ++ b0[1] = 5612; ++ b1[1] = -1393; ++ b1[0] = -1393; ++ } else { ++ ++ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ switch (chan_freq_range) { ++ case WL_CHAN_FREQ_RANGE_2G: ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; ++ target_pwr_qtrdbm[0] = ++ pi->nphy_pwrctrl_info[0].max_pwr_2g; ++ target_pwr_qtrdbm[1] = ++ pi->nphy_pwrctrl_info[1].max_pwr_2g; ++ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1; ++ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1; ++ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0; ++ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b0; ++ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b1; ++ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b1; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GL: ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; ++ target_pwr_qtrdbm[0] = ++ pi->nphy_pwrctrl_info[0].max_pwr_5gl; ++ target_pwr_qtrdbm[1] = ++ pi->nphy_pwrctrl_info[1].max_pwr_5gl; ++ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1; ++ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1; ++ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0; ++ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0; ++ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1; ++ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GM: ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; ++ target_pwr_qtrdbm[0] = ++ pi->nphy_pwrctrl_info[0].max_pwr_5gm; ++ target_pwr_qtrdbm[1] = ++ pi->nphy_pwrctrl_info[1].max_pwr_5gm; ++ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1; ++ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1; ++ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0; ++ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b0; ++ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b1; ++ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b1; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GH: ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; ++ target_pwr_qtrdbm[0] = ++ pi->nphy_pwrctrl_info[0].max_pwr_5gh; ++ target_pwr_qtrdbm[1] = ++ pi->nphy_pwrctrl_info[1].max_pwr_5gh; ++ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1; ++ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1; ++ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0; ++ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0; ++ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1; ++ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1; ++ break; ++ default: ++ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; ++ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; ++ target_pwr_qtrdbm[0] = 13 * 4; ++ target_pwr_qtrdbm[1] = 13 * 4; ++ a1[0] = -424; ++ a1[1] = -424; ++ b0[0] = 5612; ++ b0[1] = 5612; ++ b1[1] = -1393; ++ b1[0] = -1393; ++ break; ++ } ++ } ++ ++ target_pwr_qtrdbm[0] = (s8) pi->tx_power_max; ++ target_pwr_qtrdbm[1] = (s8) pi->tx_power_max; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (pi->srom_fem2g.tssipos) ++ or_phy_reg(pi, 0x1e9, (0x1 << 14)); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (core = 0; core <= 1; core++) { ++ if (PHY_IPA(pi)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TX_SSI_MUX, ++ 0xe); ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TX_SSI_MUX, ++ 0xc); ++ } ++ } ++ } else { ++ if (PHY_IPA(pi)) { ++ ++ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | ++ RADIO_2056_TX0, ++ (CHSPEC_IS5G ++ (pi->radio_chanspec)) ? ++ 0xc : 0xe); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MUX | ++ RADIO_2056_TX1, ++ (CHSPEC_IS5G ++ (pi->radio_chanspec)) ? ++ 0xc : 0xe); ++ } else { ++ ++ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | ++ RADIO_2056_TX0, 0x11); ++ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | ++ RADIO_2056_TX1, 0x11); ++ } ++ } ++ } ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); ++ (void)R_REG(&pi->regs->maccontrol); ++ udelay(1); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), ++ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0)); ++ else ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), ++ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0)); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ mod_phy_reg(pi, 0x222, (0xff << 0), ++ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0)); ++ else if (NREV_GT(pi->pubpi.phy_rev, 1)) ++ mod_phy_reg(pi, 0x222, (0xff << 0), ++ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0)); ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); ++ ++ write_phy_reg(pi, 0x1e8, (0x3 << 8) | (240 << 0)); ++ ++ write_phy_reg(pi, 0x1e9, ++ (1 << 15) | (idle_tssi[0] << 0) | (idle_tssi[1] << 8)); ++ ++ write_phy_reg(pi, 0x1ea, ++ (target_pwr_qtrdbm[0] << 0) | ++ (target_pwr_qtrdbm[1] << 8)); ++ ++ tbl_len = 64; ++ tbl_offset = 0; ++ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; ++ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { ++ ++ for (idx = 0; idx < tbl_len; idx++) { ++ num = 8 * ++ (16 * b0[tbl_id - 26] + b1[tbl_id - 26] * idx); ++ den = 32768 + a1[tbl_id - 26] * idx; ++ pwr_est = max(((4 * num + den / 2) / den), -8); ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) { ++ if (idx <= ++ (uint) (31 - idle_tssi[tbl_id - 26] + 1)) ++ pwr_est = ++ max(pwr_est, ++ target_pwr_qtrdbm ++ [tbl_id - 26] + 1); ++ } ++ regval[idx] = (u32) pwr_est; ++ } ++ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, ++ regval); ++ } ++ ++ wlc_phy_txpwr_limit_to_tbl_nphy(pi); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, 8, ++ pi->adj_pwr_tbl_nphy); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, 8, ++ pi->adj_pwr_tbl_nphy); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi) ++{ ++ u32 *tx_pwrctrl_tbl = NULL; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if ((pi->pubpi.radiorev == 4) ++ || (pi->pubpi.radiorev == 6)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_ipa_2g_2057rev4n6; ++ else if (pi->pubpi.radiorev == 3) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_ipa_2g_2057rev3; ++ else if (pi->pubpi.radiorev == 5) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_ipa_2g_2057rev5; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_ipa_2g_2057rev7; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { ++ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { ++ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; ++ } else { ++ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa; ++ } ++ } else { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g_2057; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_ipa_5g_2057rev7; ++ } else { ++ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g; ++ } ++ } ++ ++ return tx_pwrctrl_tbl; ++} ++ ++static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi) ++{ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->nphy_rssical_chanspec_2G == 0) ++ return; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0, ++ RADIO_2057_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_2G[0]); ++ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1, ++ RADIO_2057_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_2G[1]); ++ } else { ++ mod_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0, ++ RADIO_2056_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_2G[0]); ++ mod_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1, ++ RADIO_2056_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_2G[1]); ++ } ++ ++ write_phy_reg(pi, 0x1a6, ++ pi->rssical_cache.rssical_phyregs_2G[0]); ++ write_phy_reg(pi, 0x1ac, ++ pi->rssical_cache.rssical_phyregs_2G[1]); ++ write_phy_reg(pi, 0x1b2, ++ pi->rssical_cache.rssical_phyregs_2G[2]); ++ write_phy_reg(pi, 0x1b8, ++ pi->rssical_cache.rssical_phyregs_2G[3]); ++ write_phy_reg(pi, 0x1a4, ++ pi->rssical_cache.rssical_phyregs_2G[4]); ++ write_phy_reg(pi, 0x1aa, ++ pi->rssical_cache.rssical_phyregs_2G[5]); ++ write_phy_reg(pi, 0x1b0, ++ pi->rssical_cache.rssical_phyregs_2G[6]); ++ write_phy_reg(pi, 0x1b6, ++ pi->rssical_cache.rssical_phyregs_2G[7]); ++ write_phy_reg(pi, 0x1a5, ++ pi->rssical_cache.rssical_phyregs_2G[8]); ++ write_phy_reg(pi, 0x1ab, ++ pi->rssical_cache.rssical_phyregs_2G[9]); ++ write_phy_reg(pi, 0x1b1, ++ pi->rssical_cache.rssical_phyregs_2G[10]); ++ write_phy_reg(pi, 0x1b7, ++ pi->rssical_cache.rssical_phyregs_2G[11]); ++ ++ } else { ++ if (pi->nphy_rssical_chanspec_5G == 0) ++ return; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0, ++ RADIO_2057_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_5G[0]); ++ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1, ++ RADIO_2057_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_5G[1]); ++ } else { ++ mod_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0, ++ RADIO_2056_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_5G[0]); ++ mod_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1, ++ RADIO_2056_VCM_MASK, ++ pi->rssical_cache. ++ rssical_radio_regs_5G[1]); ++ } ++ ++ write_phy_reg(pi, 0x1a6, ++ pi->rssical_cache.rssical_phyregs_5G[0]); ++ write_phy_reg(pi, 0x1ac, ++ pi->rssical_cache.rssical_phyregs_5G[1]); ++ write_phy_reg(pi, 0x1b2, ++ pi->rssical_cache.rssical_phyregs_5G[2]); ++ write_phy_reg(pi, 0x1b8, ++ pi->rssical_cache.rssical_phyregs_5G[3]); ++ write_phy_reg(pi, 0x1a4, ++ pi->rssical_cache.rssical_phyregs_5G[4]); ++ write_phy_reg(pi, 0x1aa, ++ pi->rssical_cache.rssical_phyregs_5G[5]); ++ write_phy_reg(pi, 0x1b0, ++ pi->rssical_cache.rssical_phyregs_5G[6]); ++ write_phy_reg(pi, 0x1b6, ++ pi->rssical_cache.rssical_phyregs_5G[7]); ++ write_phy_reg(pi, 0x1a5, ++ pi->rssical_cache.rssical_phyregs_5G[8]); ++ write_phy_reg(pi, 0x1ab, ++ pi->rssical_cache.rssical_phyregs_5G[9]); ++ write_phy_reg(pi, 0x1b1, ++ pi->rssical_cache.rssical_phyregs_5G[10]); ++ write_phy_reg(pi, 0x1b7, ++ pi->rssical_cache.rssical_phyregs_5G[11]); ++ } ++} ++ ++static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi) ++{ ++ u16 txcal_gain[2]; ++ ++ pi->nphy_txcal_pwr_idx[0] = pi->nphy_cal_orig_pwr_idx[0]; ++ pi->nphy_txcal_pwr_idx[1] = pi->nphy_cal_orig_pwr_idx[0]; ++ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true); ++ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ txcal_gain); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F40; ++ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F40; ++ } else { ++ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F60; ++ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F60; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ txcal_gain); ++} ++ ++static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi) ++{ ++ bool save_bbmult = false; ++ u8 txcal_index_2057_rev5n7 = 0; ++ u8 txcal_index_2057_rev3n4n6 = 10; ++ ++ if (pi->use_int_tx_iqlo_cal_nphy) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) { ++ ++ pi->nphy_txcal_pwr_idx[0] = ++ txcal_index_2057_rev3n4n6; ++ pi->nphy_txcal_pwr_idx[1] = ++ txcal_index_2057_rev3n4n6; ++ wlc_phy_txpwr_index_nphy( ++ pi, 3, ++ txcal_index_2057_rev3n4n6, ++ false); ++ } else { ++ ++ pi->nphy_txcal_pwr_idx[0] = ++ txcal_index_2057_rev5n7; ++ pi->nphy_txcal_pwr_idx[1] = ++ txcal_index_2057_rev5n7; ++ wlc_phy_txpwr_index_nphy( ++ pi, 3, ++ txcal_index_2057_rev5n7, ++ false); ++ } ++ save_bbmult = true; ++ ++ } else if (NREV_LT(pi->pubpi.phy_rev, 5)) { ++ wlc_phy_cal_txgainctrl_nphy(pi, 11, false); ++ if (pi->sh->hw_phytxchain != 3) { ++ pi->nphy_txcal_pwr_idx[1] = ++ pi->nphy_txcal_pwr_idx[0]; ++ wlc_phy_txpwr_index_nphy(pi, 3, ++ pi-> ++ nphy_txcal_pwr_idx[0], ++ true); ++ save_bbmult = true; ++ } ++ ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { ++ if (PHY_IPA(pi)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ wlc_phy_cal_txgainctrl_nphy(pi, 12, ++ false); ++ } else { ++ pi->nphy_txcal_pwr_idx[0] = 80; ++ pi->nphy_txcal_pwr_idx[1] = 80; ++ wlc_phy_txpwr_index_nphy(pi, 3, 80, ++ false); ++ save_bbmult = true; ++ } ++ } else { ++ wlc_phy_internal_cal_txgain_nphy(pi); ++ save_bbmult = true; ++ } ++ ++ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { ++ if (PHY_IPA(pi)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ wlc_phy_cal_txgainctrl_nphy(pi, 12, ++ false); ++ else ++ wlc_phy_cal_txgainctrl_nphy(pi, 14, ++ false); ++ } else { ++ wlc_phy_internal_cal_txgain_nphy(pi); ++ save_bbmult = true; ++ } ++ } ++ ++ } else { ++ wlc_phy_cal_txgainctrl_nphy(pi, 10, false); ++ } ++ ++ if (save_bbmult) ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, ++ &pi->nphy_txcal_bbmult); ++} ++ ++static void ++wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value, ++ u8 core_code) ++{ ++ u16 mask; ++ u16 val; ++ u8 core; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ if (core_code == RADIO_MIMO_CORESEL_CORE1 ++ && core == PHY_CORE_1) ++ continue; ++ else if (core_code == RADIO_MIMO_CORESEL_CORE2 ++ && core == PHY_CORE_0) ++ continue; ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) { ++ ++ mask = (0x1 << 10); ++ val = 1 << 10; ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 : ++ 0x92, mask, val); ++ } ++ ++ if (field == NPHY_RfctrlIntc_override_OFF) { ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 : ++ 0x92, 0); ++ ++ wlc_phy_force_rfseq_nphy(pi, ++ NPHY_RFSEQ_RESET2RX); ++ } else if (field == NPHY_RfctrlIntc_override_TRSW) { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ mask = (0x1 << 6) | (0x1 << 7); ++ ++ val = value << 6; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ ++ or_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ (0x1 << 10)); ++ ++ and_phy_reg(pi, 0x2ff, (u16) ++ ~(0x3 << 14)); ++ or_phy_reg(pi, 0x2ff, (0x1 << 13)); ++ or_phy_reg(pi, 0x2ff, (0x1 << 0)); ++ } else { ++ ++ mask = (0x1 << 6) | ++ (0x1 << 7) | ++ (0x1 << 8) | (0x1 << 9); ++ val = value << 6; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ ++ mask = (0x1 << 0); ++ val = 1 << 0; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xe7 : 0xec, ++ mask, val); ++ ++ mask = (core == PHY_CORE_0) ? ++ (0x1 << 0) : (0x1 << 1); ++ val = 1 << ((core == PHY_CORE_0) ? ++ 0 : 1); ++ mod_phy_reg(pi, 0x78, mask, val); ++ ++ SPINWAIT(((read_phy_reg(pi, 0x78) & val) ++ != 0), 10000); ++ if (WARN(read_phy_reg(pi, 0x78) & val, ++ "HW error: override failed")) ++ return; ++ ++ mask = (0x1 << 0); ++ val = 0 << 0; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xe7 : 0xec, ++ mask, val); ++ } ++ } else if (field == NPHY_RfctrlIntc_override_PA) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ mask = (0x1 << 4) | (0x1 << 5); ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ val = value << 5; ++ else ++ val = value << 4; ++ ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ ++ or_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ (0x1 << 12)); ++ } else { ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ mask = (0x1 << 5); ++ val = value << 5; ++ } else { ++ mask = (0x1 << 4); ++ val = value << 4; ++ } ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ } ++ } else if (field == ++ NPHY_RfctrlIntc_override_EXT_LNA_PU) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ ++ mask = (0x1 << 0); ++ val = value << 0; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, val); ++ ++ mask = (0x1 << 2); ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, 0); ++ } else { ++ ++ mask = (0x1 << 2); ++ val = value << 2; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, val); ++ ++ mask = (0x1 << 0); ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, 0); ++ } ++ ++ mask = (0x1 << 11); ++ val = 1 << 11; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ } else { ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ mask = (0x1 << 0); ++ val = value << 0; ++ } else { ++ mask = (0x1 << 2); ++ val = value << 2; ++ } ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ } ++ } else if (field == ++ NPHY_RfctrlIntc_override_EXT_LNA_GAIN) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ ++ mask = (0x1 << 1); ++ val = value << 1; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, val); ++ ++ mask = (0x1 << 3); ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, 0); ++ } else { ++ ++ mask = (0x1 << 3); ++ val = value << 3; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, val); ++ ++ mask = (0x1 << 1); ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 ++ : 0x92, mask, 0); ++ } ++ ++ mask = (0x1 << 11); ++ val = 1 << 11; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ } else { ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ mask = (0x1 << 1); ++ val = value << 1; ++ } else { ++ mask = (0x1 << 3); ++ val = value << 3; ++ } ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x91 : 0x92, ++ mask, val); ++ } ++ } ++ } ++ } ++} ++ ++void ++wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower, ++ bool debug) ++{ ++ int gainctrl_loopidx; ++ uint core; ++ u16 m0m1, curr_m0m1; ++ s32 delta_power; ++ s32 txpwrindex; ++ s32 qdBm_power[2]; ++ u16 orig_BBConfig; ++ u16 phy_saveregs[4]; ++ u32 freq_test; ++ u16 ampl_test = 250; ++ uint stepsize; ++ bool phyhang_avoid_state = false; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ stepsize = 2; ++ else ++ stepsize = 1; ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ freq_test = 5000; ++ else ++ freq_test = 2500; ++ ++ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true); ++ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ phyhang_avoid_state = pi->phyhang_avoid; ++ pi->phyhang_avoid = false; ++ ++ phy_saveregs[0] = read_phy_reg(pi, 0x91); ++ phy_saveregs[1] = read_phy_reg(pi, 0x92); ++ phy_saveregs[2] = read_phy_reg(pi, 0xe7); ++ phy_saveregs[3] = read_phy_reg(pi, 0xec); ++ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 1, ++ RADIO_MIMO_CORESEL_CORE1 | ++ RADIO_MIMO_CORESEL_CORE2); ++ ++ if (!debug) { ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x2, RADIO_MIMO_CORESEL_CORE1); ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x8, RADIO_MIMO_CORESEL_CORE2); ++ } else { ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x1, RADIO_MIMO_CORESEL_CORE1); ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x7, RADIO_MIMO_CORESEL_CORE2); ++ } ++ ++ orig_BBConfig = read_phy_reg(pi, 0x01); ++ mod_phy_reg(pi, 0x01, (0x1 << 15), 0); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1); ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ txpwrindex = (s32) pi->nphy_cal_orig_pwr_idx[core]; ++ ++ for (gainctrl_loopidx = 0; gainctrl_loopidx < 2; ++ gainctrl_loopidx++) { ++ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0, ++ false); ++ ++ if (core == PHY_CORE_0) ++ curr_m0m1 = m0m1 & 0xff00; ++ else ++ curr_m0m1 = m0m1 & 0x00ff; ++ ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &curr_m0m1); ++ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &curr_m0m1); ++ ++ udelay(50); ++ ++ wlc_phy_est_tonepwr_nphy(pi, qdBm_power, ++ NPHY_CAL_TSSISAMPS); ++ ++ pi->nphy_bb_mult_save = 0; ++ wlc_phy_stopplayback_nphy(pi); ++ ++ delta_power = (dBm_targetpower * 4) - qdBm_power[core]; ++ ++ txpwrindex -= stepsize * delta_power; ++ if (txpwrindex < 0) ++ txpwrindex = 0; ++ else if (txpwrindex > 127) ++ txpwrindex = 127; ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_IS(pi->pubpi.phy_rev, 4) && ++ (pi->srom_fem5g.extpagain == 3)) { ++ if (txpwrindex < 30) ++ txpwrindex = 30; ++ } ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 5) && ++ (pi->srom_fem2g.extpagain == 3)) { ++ if (txpwrindex < 50) ++ txpwrindex = 50; ++ } ++ } ++ ++ wlc_phy_txpwr_index_nphy(pi, (1 << core), ++ (u8) txpwrindex, true); ++ } ++ ++ pi->nphy_txcal_pwr_idx[core] = (u8) txpwrindex; ++ ++ if (debug) { ++ u16 radio_gain; ++ u16 dbg_m0m1; ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &dbg_m0m1); ++ ++ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0, ++ false); ++ ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &dbg_m0m1); ++ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &dbg_m0m1); ++ ++ udelay(100); ++ ++ wlc_phy_est_tonepwr_nphy(pi, qdBm_power, ++ NPHY_CAL_TSSISAMPS); ++ ++ wlc_phy_table_read_nphy(pi, 7, 1, (0x110 + core), 16, ++ &radio_gain); ++ ++ mdelay(4000); ++ pi->nphy_bb_mult_save = 0; ++ wlc_phy_stopplayback_nphy(pi); ++ } ++ } ++ ++ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_txcal_pwr_idx[0], true); ++ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_txcal_pwr_idx[1], true); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &pi->nphy_txcal_bbmult); ++ ++ write_phy_reg(pi, 0x01, orig_BBConfig); ++ ++ write_phy_reg(pi, 0x91, phy_saveregs[0]); ++ write_phy_reg(pi, 0x92, phy_saveregs[1]); ++ write_phy_reg(pi, 0xe7, phy_saveregs[2]); ++ write_phy_reg(pi, 0xec, phy_saveregs[3]); ++ ++ pi->phyhang_avoid = phyhang_avoid_state; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void wlc_phy_savecal_nphy(struct brcms_phy *pi) ++{ ++ void *tbl_ptr; ++ int coreNum; ++ u16 *txcal_radio_regs = NULL; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 0, ++ &pi->calibration_cache. ++ rxcal_coeffs_2G); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ txcal_radio_regs = ++ pi->calibration_cache.txcal_radio_regs_2G; ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ pi->calibration_cache.txcal_radio_regs_2G[0] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_2G[1] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_2G[2] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX1); ++ pi->calibration_cache.txcal_radio_regs_2G[3] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX1); ++ ++ pi->calibration_cache.txcal_radio_regs_2G[4] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_2G[5] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_2G[6] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX1); ++ pi->calibration_cache.txcal_radio_regs_2G[7] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX1); ++ } else { ++ pi->calibration_cache.txcal_radio_regs_2G[0] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL); ++ pi->calibration_cache.txcal_radio_regs_2G[1] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL); ++ pi->calibration_cache.txcal_radio_regs_2G[2] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM); ++ pi->calibration_cache.txcal_radio_regs_2G[3] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM); ++ } ++ ++ pi->nphy_iqcal_chanspec_2G = pi->radio_chanspec; ++ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G; ++ } else { ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 0, ++ &pi->calibration_cache. ++ rxcal_coeffs_5G); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ txcal_radio_regs = ++ pi->calibration_cache.txcal_radio_regs_5G; ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ pi->calibration_cache.txcal_radio_regs_5G[0] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_5G[1] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_5G[2] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX1); ++ pi->calibration_cache.txcal_radio_regs_5G[3] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX1); ++ ++ pi->calibration_cache.txcal_radio_regs_5G[4] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_5G[5] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX0); ++ pi->calibration_cache.txcal_radio_regs_5G[6] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX1); ++ pi->calibration_cache.txcal_radio_regs_5G[7] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX1); ++ } else { ++ pi->calibration_cache.txcal_radio_regs_5G[0] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL); ++ pi->calibration_cache.txcal_radio_regs_5G[1] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL); ++ pi->calibration_cache.txcal_radio_regs_5G[2] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM); ++ pi->calibration_cache.txcal_radio_regs_5G[3] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM); ++ } ++ ++ pi->nphy_iqcal_chanspec_5G = pi->radio_chanspec; ++ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G; ++ } ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ ++ txcal_radio_regs[2 * coreNum] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_FINE_I); ++ txcal_radio_regs[2 * coreNum + 1] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_FINE_Q); ++ ++ txcal_radio_regs[2 * coreNum + 4] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_COARSE_I); ++ txcal_radio_regs[2 * coreNum + 5] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_COARSE_Q); ++ } ++ } ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 8, 80, 16, tbl_ptr); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi) ++{ ++ struct nphy_iq_comp tx_comp; ++ ++ wlc_phy_table_read_nphy(pi, 15, 4, 0x50, 16, &tx_comp); ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ, tx_comp.a0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 2, tx_comp.b0); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 4, tx_comp.a1); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 6, tx_comp.b1); ++} ++ ++static void wlc_phy_restorecal_nphy(struct brcms_phy *pi) ++{ ++ u16 *loft_comp; ++ u16 txcal_coeffs_bphy[4]; ++ u16 *tbl_ptr; ++ int coreNum; ++ u16 *txcal_radio_regs = NULL; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->nphy_iqcal_chanspec_2G == 0) ++ return; ++ ++ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G; ++ loft_comp = &pi->calibration_cache.txcal_coeffs_2G[5]; ++ } else { ++ if (pi->nphy_iqcal_chanspec_5G == 0) ++ return; ++ ++ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G; ++ loft_comp = &pi->calibration_cache.txcal_coeffs_5G[5]; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, 16, tbl_ptr); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ txcal_coeffs_bphy[0] = tbl_ptr[0]; ++ txcal_coeffs_bphy[1] = tbl_ptr[1]; ++ txcal_coeffs_bphy[2] = tbl_ptr[2]; ++ txcal_coeffs_bphy[3] = tbl_ptr[3]; ++ } else { ++ txcal_coeffs_bphy[0] = 0; ++ txcal_coeffs_bphy[1] = 0; ++ txcal_coeffs_bphy[2] = 0; ++ txcal_coeffs_bphy[3] = 0; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, 16, ++ txcal_coeffs_bphy); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, 16, loft_comp); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, 16, loft_comp); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ wlc_phy_tx_iq_war_nphy(pi); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ txcal_radio_regs = ++ pi->calibration_cache.txcal_radio_regs_2G; ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[0]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[1]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[2]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[3]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[4]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[5]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[6]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[7]); ++ } else { ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[0]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[1]); ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[2]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, ++ pi->calibration_cache. ++ txcal_radio_regs_2G[3]); ++ } ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, ++ &pi->calibration_cache. ++ rxcal_coeffs_2G); ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ txcal_radio_regs = ++ pi->calibration_cache.txcal_radio_regs_5G; ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[0]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[1]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_I | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[2]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_FINE_Q | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[3]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[4]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX0, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[5]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_I | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[6]); ++ write_radio_reg(pi, ++ RADIO_2056_TX_LOFT_COARSE_Q | ++ RADIO_2056_TX1, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[7]); ++ } else { ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[0]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[1]); ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[2]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, ++ pi->calibration_cache. ++ txcal_radio_regs_5G[3]); ++ } ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, ++ &pi->calibration_cache. ++ rxcal_coeffs_5G); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_FINE_I, ++ txcal_radio_regs[2 * coreNum]); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_FINE_Q, ++ txcal_radio_regs[2 * coreNum + 1]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_COARSE_I, ++ txcal_radio_regs[2 * coreNum + 4]); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, ++ LOFT_COARSE_Q, ++ txcal_radio_regs[2 * coreNum + 5]); ++ } ++ } ++} ++ ++static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi) ++{ ++ u32 idx; ++ u16 iqloCalbuf[7]; ++ u32 iqcomp, locomp, curr_locomp; ++ s8 locomp_i, locomp_q; ++ s8 curr_locomp_i, curr_locomp_q; ++ u32 tbl_id, tbl_len, tbl_offset; ++ u32 regval[128]; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ wlc_phy_table_read_nphy(pi, 15, 7, 80, 16, iqloCalbuf); ++ ++ tbl_len = 128; ++ tbl_offset = 320; ++ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; ++ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { ++ iqcomp = ++ (tbl_id == ++ 26) ? (((u32) (iqloCalbuf[0] & 0x3ff)) << 10) | ++ (iqloCalbuf[1] & 0x3ff) ++ : (((u32) (iqloCalbuf[2] & 0x3ff)) << 10) | ++ (iqloCalbuf[3] & 0x3ff); ++ ++ for (idx = 0; idx < tbl_len; idx++) ++ regval[idx] = iqcomp; ++ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, ++ regval); ++ } ++ ++ tbl_offset = 448; ++ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; ++ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { ++ ++ locomp = ++ (u32) ((tbl_id == 26) ? iqloCalbuf[5] : iqloCalbuf[6]); ++ locomp_i = (s8) ((locomp >> 8) & 0xff); ++ locomp_q = (s8) ((locomp) & 0xff); ++ for (idx = 0; idx < tbl_len; idx++) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ curr_locomp_i = locomp_i; ++ curr_locomp_q = locomp_q; ++ } else { ++ curr_locomp_i = (s8) ((locomp_i * ++ nphy_tpc_loscale[idx] + ++ 128) >> 8); ++ curr_locomp_q = ++ (s8) ((locomp_q * ++ nphy_tpc_loscale[idx] + ++ 128) >> 8); ++ } ++ curr_locomp = (u32) ((curr_locomp_i & 0xff) << 8); ++ curr_locomp |= (u32) (curr_locomp_q & 0xff); ++ regval[idx] = curr_locomp; ++ } ++ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, ++ regval); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX1, 0xFFFF); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX2, 0xFFFF); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi) ++{ ++ u8 tx_lpf_bw = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ tx_lpf_bw = 3; ++ else ++ tx_lpf_bw = 1; ++ ++ if (PHY_IPA(pi)) { ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ tx_lpf_bw = 5; ++ else ++ tx_lpf_bw = 4; ++ } ++ ++ write_phy_reg(pi, 0xe8, ++ (tx_lpf_bw << 0) | ++ (tx_lpf_bw << 3) | ++ (tx_lpf_bw << 6) | (tx_lpf_bw << 9)); ++ ++ if (PHY_IPA(pi)) { ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ tx_lpf_bw = 4; ++ else ++ tx_lpf_bw = 1; ++ ++ write_phy_reg(pi, 0xe9, ++ (tx_lpf_bw << 0) | ++ (tx_lpf_bw << 3) | ++ (tx_lpf_bw << 6) | (tx_lpf_bw << 9)); ++ } ++ } ++} ++ ++static void ++wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi, u16 reduction_factr) ++{ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) && ++ CHSPEC_IS40(pi->radio_chanspec)) { ++ if (!pi->nphy_anarxlpf_adjusted) { ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_LPC | ++ RADIO_2056_RX0), ++ ((pi->nphy_rccal_value + ++ reduction_factr) | 0x80)); ++ ++ pi->nphy_anarxlpf_adjusted = true; ++ } ++ } else { ++ if (pi->nphy_anarxlpf_adjusted) { ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_LPC | ++ RADIO_2056_RX0), ++ (pi->nphy_rccal_value | 0x80)); ++ ++ pi->nphy_anarxlpf_adjusted = false; ++ } ++ } ++ } ++} ++ ++static void ++wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi, int ntones, ++ int *tone_id_buf, u32 *noise_var_buf) ++{ ++ int i; ++ u32 offset; ++ int tone_id; ++ int tbllen = ++ CHSPEC_IS40(pi->radio_chanspec) ? ++ NPHY_NOISEVAR_TBLLEN40 : NPHY_NOISEVAR_TBLLEN20; ++ ++ if (pi->nphy_noisevars_adjusted) { ++ for (i = 0; i < pi->nphy_saved_noisevars.bufcount; i++) { ++ tone_id = pi->nphy_saved_noisevars.tone_id[i]; ++ offset = (tone_id >= 0) ? ++ ((tone_id * ++ 2) + 1) : (tbllen + (tone_id * 2) + 1); ++ wlc_phy_table_write_nphy( ++ pi, NPHY_TBL_ID_NOISEVAR, 1, ++ offset, 32, ++ &pi->nphy_saved_noisevars.min_noise_vars[i]); ++ } ++ ++ pi->nphy_saved_noisevars.bufcount = 0; ++ pi->nphy_noisevars_adjusted = false; ++ } ++ ++ if ((noise_var_buf != NULL) && (tone_id_buf != NULL)) { ++ pi->nphy_saved_noisevars.bufcount = 0; ++ ++ for (i = 0; i < ntones; i++) { ++ tone_id = tone_id_buf[i]; ++ offset = (tone_id >= 0) ? ++ ((tone_id * 2) + 1) : ++ (tbllen + (tone_id * 2) + 1); ++ pi->nphy_saved_noisevars.tone_id[i] = tone_id; ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ offset, 32, ++ &pi->nphy_saved_noisevars. ++ min_noise_vars[i]); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, ++ offset, 32, &noise_var_buf[i]); ++ pi->nphy_saved_noisevars.bufcount++; ++ } ++ ++ pi->nphy_noisevars_adjusted = true; ++ } ++} ++ ++static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr) ++{ ++ u16 regval; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) && ++ CHSPEC_IS40(pi->radio_chanspec)) { ++ if (!pi->nphy_crsminpwr_adjusted) { ++ regval = read_phy_reg(pi, 0x27d); ++ pi->nphy_crsminpwr[0] = regval & 0xff; ++ regval &= 0xff00; ++ regval |= (u16) minpwr; ++ write_phy_reg(pi, 0x27d, regval); ++ ++ regval = read_phy_reg(pi, 0x280); ++ pi->nphy_crsminpwr[1] = regval & 0xff; ++ regval &= 0xff00; ++ regval |= (u16) minpwr; ++ write_phy_reg(pi, 0x280, regval); ++ ++ regval = read_phy_reg(pi, 0x283); ++ pi->nphy_crsminpwr[2] = regval & 0xff; ++ regval &= 0xff00; ++ regval |= (u16) minpwr; ++ write_phy_reg(pi, 0x283, regval); ++ ++ pi->nphy_crsminpwr_adjusted = true; ++ } ++ } else { ++ if (pi->nphy_crsminpwr_adjusted) { ++ regval = read_phy_reg(pi, 0x27d); ++ regval &= 0xff00; ++ regval |= pi->nphy_crsminpwr[0]; ++ write_phy_reg(pi, 0x27d, regval); ++ ++ regval = read_phy_reg(pi, 0x280); ++ regval &= 0xff00; ++ regval |= pi->nphy_crsminpwr[1]; ++ write_phy_reg(pi, 0x280, regval); ++ ++ regval = read_phy_reg(pi, 0x283); ++ regval &= 0xff00; ++ regval |= pi->nphy_crsminpwr[2]; ++ write_phy_reg(pi, 0x283, regval); ++ ++ pi->nphy_crsminpwr_adjusted = false; ++ } ++ } ++ } ++} ++ ++static void wlc_phy_spurwar_nphy(struct brcms_phy *pi) ++{ ++ u16 cur_channel = 0; ++ int nphy_adj_tone_id_buf[] = { 57, 58 }; ++ u32 nphy_adj_noise_var_buf[] = { 0x3ff, 0x3ff }; ++ bool isAdjustNoiseVar = false; ++ uint numTonesAdjust = 0; ++ u32 tempval = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ cur_channel = CHSPEC_CHANNEL(pi->radio_chanspec); ++ ++ if (pi->nphy_gband_spurwar_en) { ++ ++ wlc_phy_adjust_rx_analpfbw_nphy( ++ pi, ++ NPHY_ANARXLPFBW_REDUCTIONFACT); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((cur_channel == 11) ++ && CHSPEC_IS40(pi->radio_chanspec)) ++ wlc_phy_adjust_min_noisevar_nphy( ++ pi, 2, ++ nphy_adj_tone_id_buf, ++ nphy_adj_noise_var_buf); ++ else ++ wlc_phy_adjust_min_noisevar_nphy(pi, 0, ++ NULL, ++ NULL); ++ } ++ ++ wlc_phy_adjust_crsminpwr_nphy(pi, ++ NPHY_ADJUSTED_MINCRSPOWER); ++ } ++ ++ if ((pi->nphy_gband_spurwar2_en) ++ && CHSPEC_IS2G(pi->radio_chanspec)) { ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) { ++ switch (cur_channel) { ++ case 3: ++ nphy_adj_tone_id_buf[0] = 57; ++ nphy_adj_tone_id_buf[1] = 58; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x25f; ++ isAdjustNoiseVar = true; ++ break; ++ case 4: ++ nphy_adj_tone_id_buf[0] = 41; ++ nphy_adj_tone_id_buf[1] = 42; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x25f; ++ isAdjustNoiseVar = true; ++ break; ++ case 5: ++ nphy_adj_tone_id_buf[0] = 25; ++ nphy_adj_tone_id_buf[1] = 26; ++ nphy_adj_noise_var_buf[0] = 0x24f; ++ nphy_adj_noise_var_buf[1] = 0x25f; ++ isAdjustNoiseVar = true; ++ break; ++ case 6: ++ nphy_adj_tone_id_buf[0] = 9; ++ nphy_adj_tone_id_buf[1] = 10; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x24f; ++ isAdjustNoiseVar = true; ++ break; ++ case 7: ++ nphy_adj_tone_id_buf[0] = 121; ++ nphy_adj_tone_id_buf[1] = 122; ++ nphy_adj_noise_var_buf[0] = 0x18f; ++ nphy_adj_noise_var_buf[1] = 0x24f; ++ isAdjustNoiseVar = true; ++ break; ++ case 8: ++ nphy_adj_tone_id_buf[0] = 105; ++ nphy_adj_tone_id_buf[1] = 106; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x25f; ++ isAdjustNoiseVar = true; ++ break; ++ case 9: ++ nphy_adj_tone_id_buf[0] = 89; ++ nphy_adj_tone_id_buf[1] = 90; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x24f; ++ isAdjustNoiseVar = true; ++ break; ++ case 10: ++ nphy_adj_tone_id_buf[0] = 73; ++ nphy_adj_tone_id_buf[1] = 74; ++ nphy_adj_noise_var_buf[0] = 0x22f; ++ nphy_adj_noise_var_buf[1] = 0x24f; ++ isAdjustNoiseVar = true; ++ break; ++ default: ++ isAdjustNoiseVar = false; ++ break; ++ } ++ } ++ ++ if (isAdjustNoiseVar) { ++ numTonesAdjust = sizeof(nphy_adj_tone_id_buf) / ++ sizeof(nphy_adj_tone_id_buf[0]); ++ ++ wlc_phy_adjust_min_noisevar_nphy( ++ pi, ++ numTonesAdjust, ++ nphy_adj_tone_id_buf, ++ nphy_adj_noise_var_buf); ++ ++ tempval = 0; ++ ++ } else { ++ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL, ++ NULL); ++ } ++ } ++ ++ if ((pi->nphy_aband_spurwar_en) && ++ (CHSPEC_IS5G(pi->radio_chanspec))) { ++ switch (cur_channel) { ++ case 54: ++ nphy_adj_tone_id_buf[0] = 32; ++ nphy_adj_noise_var_buf[0] = 0x25f; ++ break; ++ case 38: ++ case 102: ++ case 118: ++ nphy_adj_tone_id_buf[0] = 0; ++ nphy_adj_noise_var_buf[0] = 0x0; ++ break; ++ case 134: ++ nphy_adj_tone_id_buf[0] = 32; ++ nphy_adj_noise_var_buf[0] = 0x21f; ++ break; ++ case 151: ++ nphy_adj_tone_id_buf[0] = 16; ++ nphy_adj_noise_var_buf[0] = 0x23f; ++ break; ++ case 153: ++ case 161: ++ nphy_adj_tone_id_buf[0] = 48; ++ nphy_adj_noise_var_buf[0] = 0x23f; ++ break; ++ default: ++ nphy_adj_tone_id_buf[0] = 0; ++ nphy_adj_noise_var_buf[0] = 0x0; ++ break; ++ } ++ ++ if (nphy_adj_tone_id_buf[0] ++ && nphy_adj_noise_var_buf[0]) ++ wlc_phy_adjust_min_noisevar_nphy( ++ pi, 1, ++ nphy_adj_tone_id_buf, ++ nphy_adj_noise_var_buf); ++ else ++ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL, ++ NULL); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ } ++} ++ ++void wlc_phy_init_nphy(struct brcms_phy *pi) ++{ ++ u16 val; ++ u16 clip1_ths[2]; ++ struct nphy_txgains target_gain; ++ u8 tx_pwr_ctrl_state; ++ bool do_nphy_cal = false; ++ uint core; ++ uint origidx, intr_val; ++ struct d11regs __iomem *regs; ++ u32 d11_clk_ctl_st; ++ bool do_rssi_cal = false; ++ ++ core = 0; ++ ++ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) ++ pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; ++ ++ if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) && ++ ((pi->sh->chippkg == BCM4717_PKG_ID) || ++ (pi->sh->chippkg == BCM4718_PKG_ID))) { ++ if ((pi->sh->boardflags & BFL_EXTLNA) && ++ (CHSPEC_IS2G(pi->radio_chanspec))) ++ ai_corereg(pi->sh->sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol), ++ 0x40, 0x40); ++ } ++ ++ if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && ++ CHSPEC_IS40(pi->radio_chanspec)) { ++ ++ regs = (struct d11regs __iomem *) ++ ai_switch_core(pi->sh->sih, ++ D11_CORE_ID, &origidx, ++ &intr_val); ++ d11_clk_ctl_st = R_REG(®s->clk_ctl_st); ++ AND_REG(®s->clk_ctl_st, ++ ~(CCS_FORCEHT | CCS_HTAREQ)); ++ ++ W_REG(®s->clk_ctl_st, d11_clk_ctl_st); ++ ++ ai_restore_core(pi->sh->sih, origidx, intr_val); ++ } ++ ++ pi->use_int_tx_iqlo_cal_nphy = ++ (PHY_IPA(pi) || ++ (NREV_GE(pi->pubpi.phy_rev, 7) || ++ (NREV_GE(pi->pubpi.phy_rev, 5) ++ && pi->sh->boardflags2 & BFL2_INTERNDET_TXIQCAL))); ++ ++ pi->internal_tx_iqlo_cal_tapoff_intpa_nphy = false; ++ ++ pi->nphy_deaf_count = 0; ++ ++ wlc_phy_tbl_init_nphy(pi); ++ ++ pi->nphy_crsminpwr_adjusted = false; ++ pi->nphy_noisevars_adjusted = false; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0xe7, 0); ++ write_phy_reg(pi, 0xec, 0); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ write_phy_reg(pi, 0x342, 0); ++ write_phy_reg(pi, 0x343, 0); ++ write_phy_reg(pi, 0x346, 0); ++ write_phy_reg(pi, 0x347, 0); ++ } ++ write_phy_reg(pi, 0xe5, 0); ++ write_phy_reg(pi, 0xe6, 0); ++ } else { ++ write_phy_reg(pi, 0xec, 0); ++ } ++ ++ write_phy_reg(pi, 0x91, 0); ++ write_phy_reg(pi, 0x92, 0); ++ if (NREV_LT(pi->pubpi.phy_rev, 6)) { ++ write_phy_reg(pi, 0x93, 0); ++ write_phy_reg(pi, 0x94, 0); ++ } ++ ++ and_phy_reg(pi, 0xa1, ~3); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0x8f, 0); ++ write_phy_reg(pi, 0xa5, 0); ++ } else { ++ write_phy_reg(pi, 0xa5, 0); ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b); ++ else if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x40); ++ ++ write_phy_reg(pi, 0x203, 32); ++ write_phy_reg(pi, 0x201, 32); ++ ++ if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD) ++ write_phy_reg(pi, 0x20d, 160); ++ else ++ write_phy_reg(pi, 0x20d, 184); ++ ++ write_phy_reg(pi, 0x13a, 200); ++ ++ write_phy_reg(pi, 0x70, 80); ++ ++ write_phy_reg(pi, 0x1ff, 48); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 8)) ++ wlc_phy_update_mimoconfig_nphy(pi, pi->n_preamble_override); ++ ++ wlc_phy_stf_chain_upd_nphy(pi); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ write_phy_reg(pi, 0x180, 0xaa8); ++ write_phy_reg(pi, 0x181, 0x9a4); ++ } ++ ++ if (PHY_IPA(pi)) { ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x298 : ++ 0x29c, (0x1ff << 7), ++ (pi->nphy_papd_epsilon_offset[core]) << 7); ++ ++ } ++ ++ wlc_phy_ipa_set_tx_digi_filts_nphy(pi); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 5)) { ++ wlc_phy_extpa_set_tx_digi_filts_nphy(pi); ++ } ++ ++ wlc_phy_workarounds_nphy(pi); ++ ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); ++ ++ val = read_phy_reg(pi, 0x01); ++ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA); ++ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA)); ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); ++ ++ wlapi_bmac_macphyclk_set(pi->sh->physhim, ON); ++ ++ wlc_phy_pa_override_nphy(pi, OFF); ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX); ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ wlc_phy_pa_override_nphy(pi, ON); ++ ++ wlc_phy_classifier_nphy(pi, 0, 0); ++ wlc_phy_clip_det_nphy(pi, 0, clip1_ths); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ wlc_phy_bphy_init_nphy(pi); ++ ++ tx_pwr_ctrl_state = pi->nphy_txpwrctrl; ++ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); ++ ++ wlc_phy_txpwr_fixpower_nphy(pi); ++ ++ wlc_phy_txpwrctrl_idle_tssi_nphy(pi); ++ ++ wlc_phy_txpwrctrl_pwr_setup_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ u32 *tx_pwrctrl_tbl = NULL; ++ u16 idx; ++ s16 pga_gn = 0; ++ s16 pad_gn = 0; ++ s32 rfpwr_offset; ++ ++ if (PHY_IPA(pi)) { ++ tx_pwrctrl_tbl = wlc_phy_get_ipa_gaintbl_nphy(pi); ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_IS(pi->pubpi.phy_rev, 3)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_5GHz_txgain_rev3; ++ else if (NREV_IS(pi->pubpi.phy_rev, 4)) ++ tx_pwrctrl_tbl = ++ (pi->srom_fem5g.extpagain == ++ 3) ? ++ nphy_tpc_5GHz_txgain_HiPwrEPA : ++ nphy_tpc_5GHz_txgain_rev4; ++ else ++ tx_pwrctrl_tbl = ++ nphy_tpc_5GHz_txgain_rev5; ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (pi->pubpi.radiorev == 5) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_epa_2057rev5; ++ else if (pi->pubpi.radiorev == 3) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_epa_2057rev3; ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 5) && ++ (pi->srom_fem2g.extpagain == 3)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_HiPwrEPA; ++ else ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_rev3; ++ } ++ } ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128, ++ 192, 32, tx_pwrctrl_tbl); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128, ++ 192, 32, tx_pwrctrl_tbl); ++ ++ pi->nphy_gmval = (u16) ((*tx_pwrctrl_tbl >> 16) & 0x7000); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ for (idx = 0; idx < 128; idx++) { ++ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf; ++ pad_gn = (tx_pwrctrl_tbl[idx] >> 19) & 0x1f; ++ rfpwr_offset = get_rf_pwr_offset(pi, pga_gn, ++ pad_gn); ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_CORE1TXPWRCTL, ++ 1, 576 + idx, 32, ++ &rfpwr_offset); ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_CORE2TXPWRCTL, ++ 1, 576 + idx, 32, ++ &rfpwr_offset); ++ } ++ } else { ++ ++ for (idx = 0; idx < 128; idx++) { ++ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf; ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ rfpwr_offset = (s16) ++ nphy_papd_pga_gain_delta_ipa_2g ++ [pga_gn]; ++ else ++ rfpwr_offset = (s16) ++ nphy_papd_pga_gain_delta_ipa_5g ++ [pga_gn]; ++ ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_CORE1TXPWRCTL, ++ 1, 576 + idx, 32, ++ &rfpwr_offset); ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_CORE2TXPWRCTL, ++ 1, 576 + idx, 32, ++ &rfpwr_offset); ++ } ++ ++ } ++ } else { ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128, ++ 192, 32, nphy_tpc_txgain); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128, ++ 192, 32, nphy_tpc_txgain); ++ } ++ ++ if (pi->sh->phyrxchain != 0x3) ++ wlc_phy_rxcore_setstate_nphy((struct brcms_phy_pub *) pi, ++ pi->sh->phyrxchain); ++ ++ if (PHY_PERICAL_MPHASE_PENDING(pi)) ++ wlc_phy_cal_perical_mphase_restart(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ do_rssi_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ? ++ (pi->nphy_rssical_chanspec_2G == 0) : ++ (pi->nphy_rssical_chanspec_5G == 0); ++ ++ if (do_rssi_cal) ++ wlc_phy_rssi_cal_nphy(pi); ++ else ++ wlc_phy_restore_rssical_nphy(pi); ++ } else { ++ wlc_phy_rssi_cal_nphy(pi); ++ } ++ ++ if (!SCAN_RM_IN_PROGRESS(pi)) ++ do_nphy_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ? ++ (pi->nphy_iqcal_chanspec_2G == 0) : ++ (pi->nphy_iqcal_chanspec_5G == 0); ++ ++ if (!pi->do_initcal) ++ do_nphy_cal = false; ++ ++ if (do_nphy_cal) { ++ ++ target_gain = wlc_phy_get_tx_gain_nphy(pi); ++ ++ if (pi->antsel_type == ANTSEL_2x3) ++ wlc_phy_antsel_init((struct brcms_phy_pub *) pi, ++ true); ++ ++ if (pi->nphy_perical != PHY_PERICAL_MPHASE) { ++ wlc_phy_rssi_cal_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ pi->nphy_cal_orig_pwr_idx[0] = ++ pi->nphy_txpwrindex[PHY_CORE_0] ++ . ++ index_internal; ++ pi->nphy_cal_orig_pwr_idx[1] = ++ pi->nphy_txpwrindex[PHY_CORE_1] ++ . ++ index_internal; ++ ++ wlc_phy_precal_txgain_nphy(pi); ++ target_gain = ++ wlc_phy_get_tx_gain_nphy(pi); ++ } ++ ++ if (wlc_phy_cal_txiqlo_nphy ++ (pi, target_gain, true, ++ false) == 0) { ++ if (wlc_phy_cal_rxiq_nphy ++ (pi, target_gain, 2, ++ false) == 0) ++ wlc_phy_savecal_nphy(pi); ++ ++ } ++ } else if (pi->mphase_cal_phase_id == ++ MPHASE_CAL_STATE_IDLE) { ++ wlc_phy_cal_perical((struct brcms_phy_pub *) pi, ++ PHY_PERICAL_PHYINIT); ++ } ++ } else { ++ wlc_phy_restorecal_nphy(pi); ++ } ++ ++ wlc_phy_txpwrctrl_coeff_setup_nphy(pi); ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); ++ ++ wlc_phy_nphy_tkip_rifs_war(pi, pi->sh->_rifs_phy); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LE(pi->pubpi.phy_rev, 6)) ++ ++ write_phy_reg(pi, 0x70, 50); ++ ++ wlc_phy_txlpfbw_nphy(pi); ++ ++ wlc_phy_spurwar_nphy(pi); ++ ++} ++ ++static void wlc_phy_resetcca_nphy(struct brcms_phy *pi) ++{ ++ u16 val; ++ ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); ++ ++ val = read_phy_reg(pi, 0x01); ++ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA); ++ udelay(1); ++ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA)); ++ ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); ++ ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++} ++ ++void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en) ++{ ++ u16 rfctrlintc_override_val; ++ ++ if (!en) { ++ ++ pi->rfctrlIntc1_save = read_phy_reg(pi, 0x91); ++ pi->rfctrlIntc2_save = read_phy_reg(pi, 0x92); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ rfctrlintc_override_val = 0x1480; ++ else if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ rfctrlintc_override_val = ++ CHSPEC_IS5G(pi->radio_chanspec) ? 0x600 : 0x480; ++ else ++ rfctrlintc_override_val = ++ CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120; ++ ++ write_phy_reg(pi, 0x91, rfctrlintc_override_val); ++ write_phy_reg(pi, 0x92, rfctrlintc_override_val); ++ } else { ++ write_phy_reg(pi, 0x91, pi->rfctrlIntc1_save); ++ write_phy_reg(pi, 0x92, pi->rfctrlIntc2_save); ++ } ++ ++} ++ ++void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi) ++{ ++ ++ u16 txrx_chain = ++ (NPHY_RfseqCoreActv_TxRxChain0 | NPHY_RfseqCoreActv_TxRxChain1); ++ bool CoreActv_override = false; ++ ++ if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN0) { ++ txrx_chain = NPHY_RfseqCoreActv_TxRxChain0; ++ CoreActv_override = true; ++ ++ if (NREV_LE(pi->pubpi.phy_rev, 2)) ++ and_phy_reg(pi, 0xa0, ~0x20); ++ } else if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN1) { ++ txrx_chain = NPHY_RfseqCoreActv_TxRxChain1; ++ CoreActv_override = true; ++ ++ if (NREV_LE(pi->pubpi.phy_rev, 2)) ++ or_phy_reg(pi, 0xa0, 0x20); ++ } ++ ++ mod_phy_reg(pi, 0xa2, ((0xf << 0) | (0xf << 4)), txrx_chain); ++ ++ if (CoreActv_override) { ++ pi->nphy_perical = PHY_PERICAL_DISABLE; ++ or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override); ++ } else { ++ pi->nphy_perical = PHY_PERICAL_MPHASE; ++ and_phy_reg(pi, 0xa1, ~NPHY_RfseqMode_CoreActv_override); ++ } ++} ++ ++void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) ++{ ++ u16 regval; ++ u16 tbl_buf[16]; ++ uint i; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ u16 tbl_opcode; ++ bool suspend; ++ ++ pi->sh->phyrxchain = rxcore_bitmask; ++ ++ if (!pi->sh->clk) ++ return; ++ ++ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!suspend) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ regval = read_phy_reg(pi, 0xa2); ++ regval &= ~(0xf << 4); ++ regval |= ((u16) (rxcore_bitmask & 0x3)) << 4; ++ write_phy_reg(pi, 0xa2, regval); ++ ++ if ((rxcore_bitmask & 0x3) != 0x3) { ++ ++ write_phy_reg(pi, 0x20e, 1); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (pi->rx2tx_biasentry == -1) { ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ ARRAY_SIZE(tbl_buf), 80, ++ 16, tbl_buf); ++ ++ for (i = 0; i < ARRAY_SIZE(tbl_buf); i++) { ++ if (tbl_buf[i] == ++ NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS) { ++ pi->rx2tx_biasentry = (u8) i; ++ tbl_opcode = ++ NPHY_REV3_RFSEQ_CMD_NOP; ++ wlc_phy_table_write_nphy( ++ pi, ++ NPHY_TBL_ID_RFSEQ, ++ 1, i, ++ 16, ++ &tbl_opcode); ++ break; ++ } else if (tbl_buf[i] == ++ NPHY_REV3_RFSEQ_CMD_END) ++ break; ++ } ++ } ++ } ++ } else { ++ ++ write_phy_reg(pi, 0x20e, 30); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (pi->rx2tx_biasentry != -1) { ++ tbl_opcode = NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ 1, pi->rx2tx_biasentry, ++ 16, &tbl_opcode); ++ pi->rx2tx_biasentry = -1; ++ } ++ } ++ } ++ ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ if (!suspend) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) ++{ ++ u16 regval, rxen_bits; ++ struct brcms_phy *pi = (struct brcms_phy *) pih; ++ ++ regval = read_phy_reg(pi, 0xa2); ++ rxen_bits = (regval >> 4) & 0xf; ++ ++ return (u8) rxen_bits; ++} ++ ++bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi) ++{ ++ return PHY_IPA(pi); ++} ++ ++void wlc_phy_cal_init_nphy(struct brcms_phy *pi) ++{ ++} ++ ++static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi) ++{ ++ ++ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); ++ and_phy_reg(pi, 0x78, RFCC_OE_POR_FORCE); ++ ++ or_phy_reg(pi, 0x78, ~RFCC_OE_POR_FORCE); ++ or_phy_reg(pi, 0x78, RFCC_CHIP0_PU); ++ ++} ++ ++static void wlc_phy_radio_init_2057(struct brcms_phy *pi) ++{ ++ struct radio_20xx_regs *regs_2057_ptr = NULL; ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7)) { ++ regs_2057_ptr = regs_2057_rev4; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 8) ++ || NREV_IS(pi->pubpi.phy_rev, 9)) { ++ switch (pi->pubpi.radiorev) { ++ case 5: ++ ++ if (pi->pubpi.radiover == 0x0) ++ regs_2057_ptr = regs_2057_rev5; ++ else if (pi->pubpi.radiover == 0x1) ++ regs_2057_ptr = regs_2057_rev5v1; ++ else ++ break; ++ ++ case 7: ++ ++ regs_2057_ptr = regs_2057_rev7; ++ break; ++ ++ case 8: ++ ++ regs_2057_ptr = regs_2057_rev8; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ wlc_phy_init_radio_regs_allbands(pi, regs_2057_ptr); ++} ++ ++static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi) ++{ ++ u16 rcal_reg = 0; ++ int i; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ if (pi->pubpi.radiorev == 5) { ++ ++ and_phy_reg(pi, 0x342, ~(0x1 << 1)); ++ ++ udelay(10); ++ ++ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x1); ++ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2, ++ 0x1); ++ } ++ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x1); ++ ++ udelay(10); ++ ++ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x3, 0x3); ++ ++ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { ++ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS); ++ if (rcal_reg & 0x1) ++ break; ++ ++ udelay(100); ++ } ++ ++ if (WARN(i == MAX_205x_RCAL_WAITLOOPS, ++ "HW error: radio calib2")) ++ return 0; ++ ++ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x2, 0x0); ++ ++ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS) & 0x3e; ++ ++ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x0); ++ if (pi->pubpi.radiorev == 5) { ++ ++ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x0); ++ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2, ++ 0x0); ++ } ++ ++ if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) { ++ ++ mod_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x3c, ++ rcal_reg); ++ mod_radio_reg(pi, RADIO_2057_BANDGAP_RCAL_TRIM, 0xf0, ++ rcal_reg << 2); ++ } ++ ++ } else if (NREV_IS(pi->pubpi.phy_rev, 3)) { ++ u16 savereg; ++ ++ savereg = ++ read_radio_reg( ++ pi, ++ RADIO_2056_SYN_PLL_MAST2 | ++ RADIO_2056_SYN); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN, ++ savereg | 0x7); ++ udelay(10); ++ ++ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, ++ 0x1); ++ udelay(10); ++ ++ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, ++ 0x9); ++ ++ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { ++ rcal_reg = read_radio_reg( ++ pi, ++ RADIO_2056_SYN_RCAL_CODE_OUT | ++ RADIO_2056_SYN); ++ if (rcal_reg & 0x80) ++ break; ++ ++ udelay(100); ++ } ++ ++ if (WARN(i == MAX_205x_RCAL_WAITLOOPS, ++ "HW error: radio calib3")) ++ return 0; ++ ++ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, ++ 0x1); ++ ++ rcal_reg = ++ read_radio_reg(pi, ++ RADIO_2056_SYN_RCAL_CODE_OUT | ++ RADIO_2056_SYN); ++ ++ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, ++ 0x0); ++ ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN, ++ savereg); ++ ++ return rcal_reg & 0x1f; ++ } ++ return rcal_reg & 0x3e; ++} ++ ++static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi) ++{ ++ u16 rccal_valid; ++ int i; ++ bool chip43226_6362A0; ++ ++ chip43226_6362A0 = ((pi->pubpi.radiorev == 3) ++ || (pi->pubpi.radiorev == 4) ++ || (pi->pubpi.radiorev == 6)); ++ ++ rccal_valid = 0; ++ if (chip43226_6362A0) { ++ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x61); ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xc0); ++ } else { ++ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x61); ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xe9); ++ } ++ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); ++ ++ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { ++ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); ++ if (rccal_valid & 0x2) ++ break; ++ ++ udelay(500); ++ } ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); ++ ++ rccal_valid = 0; ++ if (chip43226_6362A0) { ++ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x69); ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0); ++ } else { ++ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x69); ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xd5); ++ } ++ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); ++ ++ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { ++ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); ++ if (rccal_valid & 0x2) ++ break; ++ ++ udelay(500); ++ } ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); ++ ++ rccal_valid = 0; ++ if (chip43226_6362A0) { ++ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x73); ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x28); ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0); ++ } else { ++ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x73); ++ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); ++ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0x99); ++ } ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); ++ ++ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { ++ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); ++ if (rccal_valid & 0x2) ++ break; ++ ++ udelay(500); ++ } ++ ++ if (WARN(!(rccal_valid & 0x2), "HW error: radio calib4")) ++ return 0; ++ ++ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); ++ ++ return rccal_valid; ++} ++ ++static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi) ++{ ++ ++ mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1); ++ ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x78); ++ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x80); ++ mdelay(2); ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x0); ++ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x0); ++ ++ if (pi->phy_init_por) { ++ wlc_phy_radio205x_rcal(pi); ++ wlc_phy_radio2057_rccal(pi); ++ } ++ ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MASTER, 0x8, 0x0); ++} ++ ++static void wlc_phy_radio_init_2056(struct brcms_phy *pi) ++{ ++ const struct radio_regs *regs_SYN_2056_ptr = NULL; ++ const struct radio_regs *regs_TX_2056_ptr = NULL; ++ const struct radio_regs *regs_RX_2056_ptr = NULL; ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 3)) { ++ regs_SYN_2056_ptr = regs_SYN_2056; ++ regs_TX_2056_ptr = regs_TX_2056; ++ regs_RX_2056_ptr = regs_RX_2056; ++ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { ++ regs_SYN_2056_ptr = regs_SYN_2056_A1; ++ regs_TX_2056_ptr = regs_TX_2056_A1; ++ regs_RX_2056_ptr = regs_RX_2056_A1; ++ } else { ++ switch (pi->pubpi.radiorev) { ++ case 5: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev5; ++ regs_TX_2056_ptr = regs_TX_2056_rev5; ++ regs_RX_2056_ptr = regs_RX_2056_rev5; ++ break; ++ ++ case 6: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev6; ++ regs_TX_2056_ptr = regs_TX_2056_rev6; ++ regs_RX_2056_ptr = regs_RX_2056_rev6; ++ break; ++ ++ case 7: ++ case 9: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev7; ++ regs_TX_2056_ptr = regs_TX_2056_rev7; ++ regs_RX_2056_ptr = regs_RX_2056_rev7; ++ break; ++ ++ case 8: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev8; ++ regs_TX_2056_ptr = regs_TX_2056_rev8; ++ regs_RX_2056_ptr = regs_RX_2056_rev8; ++ break; ++ ++ case 11: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev11; ++ regs_TX_2056_ptr = regs_TX_2056_rev11; ++ regs_RX_2056_ptr = regs_RX_2056_rev11; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ wlc_phy_init_radio_regs(pi, regs_SYN_2056_ptr, (u16) RADIO_2056_SYN); ++ ++ wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX0); ++ ++ wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX1); ++ ++ wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX0); ++ ++ wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX1); ++} ++ ++static void wlc_phy_radio_postinit_2056(struct brcms_phy *pi) ++{ ++ mod_radio_reg(pi, RADIO_2056_SYN_COM_CTRL, 0xb, 0xb); ++ ++ mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x2); ++ mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x2); ++ udelay(1000); ++ mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x0); ++ ++ if ((pi->sh->boardflags2 & BFL2_LEGACY) ++ || (pi->sh->boardflags2 & BFL2_XTALBUFOUTEN)) ++ mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xf4, 0x0); ++ else ++ mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xfc, 0x0); ++ ++ mod_radio_reg(pi, RADIO_2056_SYN_RCCAL_CTRL0, 0x1, 0x0); ++ ++ if (pi->phy_init_por) ++ wlc_phy_radio205x_rcal(pi); ++} ++ ++static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi) ++{ ++ ++ and_phy_reg(pi, 0x78, ~RFCC_POR_FORCE); ++ or_phy_reg(pi, 0x78, RFCC_CHIP0_PU | RFCC_OE_POR_FORCE); ++ ++ or_phy_reg(pi, 0x78, RFCC_POR_FORCE); ++} ++ ++static void wlc_phy_radio_init_2055(struct brcms_phy *pi) ++{ ++ wlc_phy_init_radio_regs(pi, regs_2055, RADIO_DEFAULT_CORE); ++} ++ ++static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi) ++{ ++ ++ and_radio_reg(pi, RADIO_2055_MASTER_CNTRL1, ++ ~(RADIO_2055_JTAGCTRL_MASK | RADIO_2055_JTAGSYNC_MASK)); ++ ++ if (((pi->sh->sromrev >= 4) ++ && !(pi->sh->boardflags2 & BFL2_RXBB_INT_REG_DIS)) ++ || ((pi->sh->sromrev < 4))) { ++ and_radio_reg(pi, RADIO_2055_CORE1_RXBB_REGULATOR, 0x7F); ++ and_radio_reg(pi, RADIO_2055_CORE2_RXBB_REGULATOR, 0x7F); ++ } ++ ++ mod_radio_reg(pi, RADIO_2055_RRCCAL_N_OPT_SEL, 0x3F, 0x2C); ++ write_radio_reg(pi, RADIO_2055_CAL_MISC, 0x3C); ++ ++ and_radio_reg(pi, RADIO_2055_CAL_MISC, ++ ~(RADIO_2055_RRCAL_START | RADIO_2055_RRCAL_RST_N)); ++ ++ or_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, RADIO_2055_CAL_LPO_ENABLE); ++ ++ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_RST_N); ++ ++ udelay(1000); ++ ++ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_START); ++ ++ SPINWAIT(((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) & ++ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE), 2000); ++ ++ if (WARN((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) & ++ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE, ++ "HW error: radio calibration1\n")) ++ return; ++ ++ and_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, ++ ~(RADIO_2055_CAL_LPO_ENABLE)); ++ ++ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec); ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_LPF, 9); ++ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_LPF, 9); ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_MIDAC_HIPAS, 0x83); ++ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_MIDAC_HIPAS, 0x83); ++ ++ mod_radio_reg(pi, RADIO_2055_CORE1_LNA_GAINBST, ++ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE); ++ mod_radio_reg(pi, RADIO_2055_CORE2_LNA_GAINBST, ++ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE); ++ if (pi->nphy_gain_boost) { ++ and_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1, ++ ~(RADIO_2055_GAINBST_DISABLE)); ++ and_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1, ++ ~(RADIO_2055_GAINBST_DISABLE)); ++ } else { ++ or_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1, ++ RADIO_2055_GAINBST_DISABLE); ++ or_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1, ++ RADIO_2055_GAINBST_DISABLE); ++ } ++ ++ udelay(2); ++} ++ ++void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on) ++{ ++ if (on) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (!pi->radio_is_on) { ++ wlc_phy_radio_preinit_205x(pi); ++ wlc_phy_radio_init_2057(pi); ++ wlc_phy_radio_postinit_2057(pi); ++ } ++ ++ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, ++ pi->radio_chanspec); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ wlc_phy_radio_preinit_205x(pi); ++ wlc_phy_radio_init_2056(pi); ++ wlc_phy_radio_postinit_2056(pi); ++ ++ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, ++ pi->radio_chanspec); ++ } else { ++ wlc_phy_radio_preinit_2055(pi); ++ wlc_phy_radio_init_2055(pi); ++ wlc_phy_radio_postinit_2055(pi); ++ } ++ ++ pi->radio_is_on = true; ++ ++ } else { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) ++ && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); ++ mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x0); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_PADA_BOOST_TUNE | ++ RADIO_2056_TX0, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PADG_BOOST_TUNE | ++ RADIO_2056_TX0, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PGAA_BOOST_TUNE | ++ RADIO_2056_TX0, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PGAG_BOOST_TUNE | ++ RADIO_2056_TX0, 0); ++ mod_radio_reg(pi, ++ RADIO_2056_TX_MIXA_BOOST_TUNE | ++ RADIO_2056_TX0, 0xf0, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_MIXG_BOOST_TUNE | ++ RADIO_2056_TX0, 0); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_PADA_BOOST_TUNE | ++ RADIO_2056_TX1, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PADG_BOOST_TUNE | ++ RADIO_2056_TX1, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PGAA_BOOST_TUNE | ++ RADIO_2056_TX1, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_PGAG_BOOST_TUNE | ++ RADIO_2056_TX1, 0); ++ mod_radio_reg(pi, ++ RADIO_2056_TX_MIXA_BOOST_TUNE | ++ RADIO_2056_TX1, 0xf0, 0); ++ write_radio_reg(pi, ++ RADIO_2056_TX_MIXG_BOOST_TUNE | ++ RADIO_2056_TX1, 0); ++ ++ pi->radio_is_on = false; ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 8)) { ++ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); ++ pi->radio_is_on = false; ++ } ++ ++ } ++} ++ ++static bool ++wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f, ++ const struct chan_info_nphy_radio2057 **t0, ++ const struct chan_info_nphy_radio205x **t1, ++ const struct chan_info_nphy_radio2057_rev5 **t2, ++ const struct chan_info_nphy_2055 **t3) ++{ ++ uint i; ++ const struct chan_info_nphy_radio2057 *chan_info_tbl_p_0 = NULL; ++ const struct chan_info_nphy_radio205x *chan_info_tbl_p_1 = NULL; ++ const struct chan_info_nphy_radio2057_rev5 *chan_info_tbl_p_2 = NULL; ++ u32 tbl_len = 0; ++ ++ int freq = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7)) { ++ ++ chan_info_tbl_p_0 = chan_info_nphyrev7_2057_rev4; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev7_2057_rev4); ++ ++ } else if (NREV_IS(pi->pubpi.phy_rev, 8) ++ || NREV_IS(pi->pubpi.phy_rev, 9)) { ++ switch (pi->pubpi.radiorev) { ++ ++ case 5: ++ ++ if (pi->pubpi.radiover == 0x0) { ++ ++ chan_info_tbl_p_2 = ++ chan_info_nphyrev8_2057_rev5; ++ tbl_len = ARRAY_SIZE( ++ chan_info_nphyrev8_2057_rev5); ++ ++ } else if (pi->pubpi.radiover == 0x1) { ++ ++ chan_info_tbl_p_2 = ++ chan_info_nphyrev9_2057_rev5v1; ++ tbl_len = ARRAY_SIZE( ++ chan_info_nphyrev9_2057_rev5v1); ++ ++ } ++ break; ++ ++ case 7: ++ chan_info_tbl_p_0 = ++ chan_info_nphyrev8_2057_rev7; ++ tbl_len = ARRAY_SIZE( ++ chan_info_nphyrev8_2057_rev7); ++ break; ++ ++ case 8: ++ chan_info_tbl_p_0 = ++ chan_info_nphyrev8_2057_rev8; ++ tbl_len = ARRAY_SIZE( ++ chan_info_nphyrev8_2057_rev8); ++ break; ++ ++ default: ++ break; ++ } ++ } else if (NREV_IS(pi->pubpi.phy_rev, 16)) { ++ ++ chan_info_tbl_p_0 = chan_info_nphyrev8_2057_rev8; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev8_2057_rev8); ++ } else { ++ goto fail; ++ } ++ ++ for (i = 0; i < tbl_len; i++) { ++ if (pi->pubpi.radiorev == 5) { ++ ++ if (chan_info_tbl_p_2[i].chan == channel) ++ break; ++ } else { ++ ++ if (chan_info_tbl_p_0[i].chan == channel) ++ break; ++ } ++ } ++ ++ if (i >= tbl_len) ++ goto fail; ++ ++ if (pi->pubpi.radiorev == 5) { ++ *t2 = &chan_info_tbl_p_2[i]; ++ freq = chan_info_tbl_p_2[i].freq; ++ } else { ++ *t0 = &chan_info_tbl_p_0[i]; ++ freq = chan_info_tbl_p_0[i].freq; ++ } ++ ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (NREV_IS(pi->pubpi.phy_rev, 3)) { ++ chan_info_tbl_p_1 = chan_info_nphyrev3_2056; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev3_2056); ++ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { ++ chan_info_tbl_p_1 = chan_info_nphyrev4_2056_A1; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev4_2056_A1); ++ } else if (NREV_IS(pi->pubpi.phy_rev, 5) ++ || NREV_IS(pi->pubpi.phy_rev, 6)) { ++ switch (pi->pubpi.radiorev) { ++ case 5: ++ chan_info_tbl_p_1 = chan_info_nphyrev5_2056v5; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev5_2056v5); ++ break; ++ case 6: ++ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v6; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v6); ++ break; ++ case 7: ++ case 9: ++ chan_info_tbl_p_1 = chan_info_nphyrev5n6_2056v7; ++ tbl_len = ++ ARRAY_SIZE(chan_info_nphyrev5n6_2056v7); ++ break; ++ case 8: ++ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v8; ++ tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v8); ++ break; ++ case 11: ++ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v11; ++ tbl_len = ARRAY_SIZE( ++ chan_info_nphyrev6_2056v11); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ for (i = 0; i < tbl_len; i++) { ++ if (chan_info_tbl_p_1[i].chan == channel) ++ break; ++ } ++ ++ if (i >= tbl_len) ++ goto fail; ++ ++ *t1 = &chan_info_tbl_p_1[i]; ++ freq = chan_info_tbl_p_1[i].freq; ++ ++ } else { ++ for (i = 0; i < ARRAY_SIZE(chan_info_nphy_2055); i++) ++ if (chan_info_nphy_2055[i].chan == channel) ++ break; ++ ++ if (i >= ARRAY_SIZE(chan_info_nphy_2055)) ++ goto fail; ++ ++ *t3 = &chan_info_nphy_2055[i]; ++ freq = chan_info_nphy_2055[i].freq; ++ } ++ ++ *f = freq; ++ return true; ++ ++fail: ++ *f = WL_CHAN_FREQ_RANGE_2G; ++ return false; ++} ++ ++u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint channel) ++{ ++ int freq; ++ const struct chan_info_nphy_radio2057 *t0 = NULL; ++ const struct chan_info_nphy_radio205x *t1 = NULL; ++ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL; ++ const struct chan_info_nphy_2055 *t3 = NULL; ++ ++ if (channel == 0) ++ channel = CHSPEC_CHANNEL(pi->radio_chanspec); ++ ++ wlc_phy_chan2freq_nphy(pi, channel, &freq, &t0, &t1, &t2, &t3); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ return WL_CHAN_FREQ_RANGE_2G; ++ ++ if ((freq >= BASE_LOW_5G_CHAN) && (freq < BASE_MID_5G_CHAN)) ++ return WL_CHAN_FREQ_RANGE_5GL; ++ else if ((freq >= BASE_MID_5G_CHAN) && (freq < BASE_HIGH_5G_CHAN)) ++ return WL_CHAN_FREQ_RANGE_5GM; ++ else ++ return WL_CHAN_FREQ_RANGE_5GH; ++} ++ ++static void ++wlc_phy_chanspec_radio2055_setup(struct brcms_phy *pi, ++ const struct chan_info_nphy_2055 *ci) ++{ ++ ++ write_radio_reg(pi, RADIO_2055_PLL_REF, ci->RF_pll_ref); ++ write_radio_reg(pi, RADIO_2055_RF_PLL_MOD0, ci->RF_rf_pll_mod0); ++ write_radio_reg(pi, RADIO_2055_RF_PLL_MOD1, ci->RF_rf_pll_mod1); ++ write_radio_reg(pi, RADIO_2055_VCO_CAP_TAIL, ci->RF_vco_cap_tail); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_VCO_CAL1, ci->RF_vco_cal1); ++ write_radio_reg(pi, RADIO_2055_VCO_CAL2, ci->RF_vco_cal2); ++ write_radio_reg(pi, RADIO_2055_PLL_LF_C1, ci->RF_pll_lf_c1); ++ write_radio_reg(pi, RADIO_2055_PLL_LF_R1, ci->RF_pll_lf_r1); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_PLL_LF_C2, ci->RF_pll_lf_c2); ++ write_radio_reg(pi, RADIO_2055_LGBUF_CEN_BUF, ci->RF_lgbuf_cen_buf); ++ write_radio_reg(pi, RADIO_2055_LGEN_TUNE1, ci->RF_lgen_tune1); ++ write_radio_reg(pi, RADIO_2055_LGEN_TUNE2, ci->RF_lgen_tune2); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_A_TUNE, ++ ci->RF_core1_lgbuf_a_tune); ++ write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_G_TUNE, ++ ci->RF_core1_lgbuf_g_tune); ++ write_radio_reg(pi, RADIO_2055_CORE1_RXRF_REG1, ci->RF_core1_rxrf_reg1); ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_PGA_PAD_TN, ++ ci->RF_core1_tx_pga_pad_tn); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_TX_MX_BGTRIM, ++ ci->RF_core1_tx_mx_bgtrim); ++ write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_A_TUNE, ++ ci->RF_core2_lgbuf_a_tune); ++ write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_G_TUNE, ++ ci->RF_core2_lgbuf_g_tune); ++ write_radio_reg(pi, RADIO_2055_CORE2_RXRF_REG1, ci->RF_core2_rxrf_reg1); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_PGA_PAD_TN, ++ ci->RF_core2_tx_pga_pad_tn); ++ write_radio_reg(pi, RADIO_2055_CORE2_TX_MX_BGTRIM, ++ ci->RF_core2_tx_mx_bgtrim); ++ ++ udelay(50); ++ ++ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x05); ++ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x45); ++ ++ BRCMS_PHY_WAR_PR51571(pi); ++ ++ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x65); ++ ++ udelay(300); ++} ++ ++static void ++wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, ++ const struct chan_info_nphy_radio205x *ci) ++{ ++ const struct radio_regs *regs_SYN_2056_ptr = NULL; ++ ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_VCOCAL1 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_vcocal1); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL2 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_vcocal2); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_REFDIV | RADIO_2056_SYN, ++ ci->RF_SYN_pll_refdiv); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD2 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_mmd2); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD1 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_mmd1); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_loopfilter1); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_loopfilter2); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER3 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_loopfilter3); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_loopfilter4); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER5 | RADIO_2056_SYN, ++ ci->RF_SYN_pll_loopfilter5); ++ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR27 | RADIO_2056_SYN, ++ ci->RF_SYN_reserved_addr27); ++ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR28 | RADIO_2056_SYN, ++ ci->RF_SYN_reserved_addr28); ++ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR29 | RADIO_2056_SYN, ++ ci->RF_SYN_reserved_addr29); ++ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_VCOBUF1 | RADIO_2056_SYN, ++ ci->RF_SYN_logen_VCOBUF1); ++ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_MIXER2 | RADIO_2056_SYN, ++ ci->RF_SYN_logen_MIXER2); ++ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF3 | RADIO_2056_SYN, ++ ci->RF_SYN_logen_BUF3); ++ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF4 | RADIO_2056_SYN, ++ ci->RF_SYN_logen_BUF4); ++ ++ write_radio_reg(pi, ++ RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX0, ++ ci->RF_RX0_lnaa_tune); ++ write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX0, ++ ci->RF_RX0_lnag_tune); ++ write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_intpaa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_intpag_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_pada_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_padg_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_pgaa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_pgag_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_mixa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX0, ++ ci->RF_TX0_mixg_boost_tune); ++ ++ write_radio_reg(pi, ++ RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX1, ++ ci->RF_RX1_lnaa_tune); ++ write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX1, ++ ci->RF_RX1_lnag_tune); ++ write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_intpaa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_intpag_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_pada_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_padg_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_pgaa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_pgag_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_mixa_boost_tune); ++ write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX1, ++ ci->RF_TX1_mixg_boost_tune); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 3)) ++ regs_SYN_2056_ptr = regs_SYN_2056; ++ else if (NREV_IS(pi->pubpi.phy_rev, 4)) ++ regs_SYN_2056_ptr = regs_SYN_2056_A1; ++ else { ++ switch (pi->pubpi.radiorev) { ++ case 5: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev5; ++ break; ++ case 6: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev6; ++ break; ++ case 7: ++ case 9: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev7; ++ break; ++ case 8: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev8; ++ break; ++ case 11: ++ regs_SYN_2056_ptr = regs_SYN_2056_rev11; ++ break; ++ } ++ } ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | ++ RADIO_2056_SYN, ++ (u16) regs_SYN_2056_ptr[0x49 - 2].init_g); ++ else ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | ++ RADIO_2056_SYN, ++ (u16) regs_SYN_2056_ptr[0x49 - 2].init_a); ++ ++ if (pi->sh->boardflags2 & BFL2_GPLL_WAR) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | ++ RADIO_2056_SYN, 0x1f); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | ++ RADIO_2056_SYN, 0x1f); ++ ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_LOOPFILTER4 | ++ RADIO_2056_SYN, 0xb); ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_CP2 | ++ RADIO_2056_SYN, 0x14); ++ } ++ } ++ ++ if ((pi->sh->boardflags2 & BFL2_GPLL_WAR2) && ++ (CHSPEC_IS2G(pi->radio_chanspec))) { ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN, ++ 0x1f); ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, ++ 0x1f); ++ write_radio_reg(pi, ++ RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN, ++ 0xb); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | RADIO_2056_SYN, ++ 0x20); ++ } ++ ++ if (pi->sh->boardflags2 & BFL2_APLL_WAR) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | ++ RADIO_2056_SYN, 0x1f); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | ++ RADIO_2056_SYN, 0x1f); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | ++ RADIO_2056_SYN, 0x5); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | ++ RADIO_2056_SYN, 0xc); ++ } ++ } ++ ++ if (PHY_IPA(pi) && CHSPEC_IS2G(pi->radio_chanspec)) { ++ u16 pag_boost_tune; ++ u16 padg_boost_tune; ++ u16 pgag_boost_tune; ++ u16 mixg_boost_tune; ++ u16 bias, cascbias; ++ uint core; ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 5)) { ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PADG_IDAC, 0xcc); ++ ++ bias = 0x25; ++ cascbias = 0x20; ++ ++ if ((pi->sh->chip == ++ BCM43224_CHIP_ID) ++ || (pi->sh->chip == ++ BCM43225_CHIP_ID)) { ++ if (pi->sh->chippkg == ++ BCM43224_FAB_SMIC) { ++ bias = 0x2a; ++ cascbias = 0x38; ++ } ++ } ++ ++ pag_boost_tune = 0x4; ++ pgag_boost_tune = 0x03; ++ padg_boost_tune = 0x77; ++ mixg_boost_tune = 0x65; ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_IMAIN_STAT, bias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_IAUX_STAT, bias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_CASCBIAS, cascbias); ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_BOOST_TUNE, ++ pag_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PGAG_BOOST_TUNE, ++ pgag_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PADG_BOOST_TUNE, ++ padg_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ MIXG_BOOST_TUNE, ++ mixg_boost_tune); ++ } else { ++ ++ bias = (pi->bw == WL_CHANSPEC_BW_40) ? ++ 0x40 : 0x20; ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_IMAIN_STAT, bias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_IAUX_STAT, bias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_CASCBIAS, 0x30); ++ } ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, PA_SPARE1, ++ 0xee); ++ } ++ } ++ ++ if (PHY_IPA(pi) && NREV_IS(pi->pubpi.phy_rev, 6) ++ && CHSPEC_IS5G(pi->radio_chanspec)) { ++ u16 paa_boost_tune; ++ u16 pada_boost_tune; ++ u16 pgaa_boost_tune; ++ u16 mixa_boost_tune; ++ u16 freq, pabias, cascbias; ++ uint core; ++ ++ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec)); ++ ++ if (freq < 5150) { ++ ++ paa_boost_tune = 0xa; ++ pada_boost_tune = 0x77; ++ pgaa_boost_tune = 0xf; ++ mixa_boost_tune = 0xf; ++ } else if (freq < 5340) { ++ ++ paa_boost_tune = 0x8; ++ pada_boost_tune = 0x77; ++ pgaa_boost_tune = 0xfb; ++ mixa_boost_tune = 0xf; ++ } else if (freq < 5650) { ++ ++ paa_boost_tune = 0x0; ++ pada_boost_tune = 0x77; ++ pgaa_boost_tune = 0xb; ++ mixa_boost_tune = 0xf; ++ } else { ++ ++ paa_boost_tune = 0x0; ++ pada_boost_tune = 0x77; ++ if (freq != 5825) ++ pgaa_boost_tune = -(int)(freq - 18) / 36 + 168; ++ else ++ pgaa_boost_tune = 6; ++ ++ mixa_boost_tune = 0xf; ++ } ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_BOOST_TUNE, paa_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PADA_BOOST_TUNE, pada_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PGAA_BOOST_TUNE, pgaa_boost_tune); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ MIXA_BOOST_TUNE, mixa_boost_tune); ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ TXSPARE1, 0x30); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PA_SPARE2, 0xee); ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ PADA_CASCBIAS, 0x3); ++ ++ cascbias = 0x30; ++ ++ if ((pi->sh->chip == BCM43224_CHIP_ID) || ++ (pi->sh->chip == BCM43225_CHIP_ID)) { ++ if (pi->sh->chippkg == BCM43224_FAB_SMIC) ++ cascbias = 0x35; ++ } ++ ++ pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias; ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_IAUX_STAT, pabias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_IMAIN_STAT, pabias); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_CASCBIAS, cascbias); ++ } ++ } ++ ++ udelay(50); ++ ++ wlc_phy_radio205x_vcocal_nphy(pi); ++} ++ ++void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi) ++{ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x0); ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04, 0x0); ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04, ++ (1 << 2)); ++ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x01); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL12, 0x0); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x18); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38); ++ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x39); ++ } ++ ++ udelay(300); ++} ++ ++static void ++wlc_phy_chanspec_radio2057_setup( ++ struct brcms_phy *pi, ++ const struct chan_info_nphy_radio2057 *ci, ++ const struct chan_info_nphy_radio2057_rev5 * ++ ci2) ++{ ++ int coreNum; ++ u16 txmix2g_tune_boost_pu = 0; ++ u16 pad2g_tune_pus = 0; ++ ++ if (pi->pubpi.radiorev == 5) { ++ ++ write_radio_reg(pi, ++ RADIO_2057_VCOCAL_COUNTVAL0, ++ ci2->RF_vcocal_countval0); ++ write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1, ++ ci2->RF_vcocal_countval1); ++ write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE, ++ ci2->RF_rfpll_refmaster_sparextalsize); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ ci2->RF_rfpll_loopfilter_r1); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ ci2->RF_rfpll_loopfilter_c2); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ ci2->RF_rfpll_loopfilter_c1); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, ++ ci2->RF_cp_kpd_idac); ++ write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci2->RF_rfpll_mmd0); ++ write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci2->RF_rfpll_mmd1); ++ write_radio_reg(pi, ++ RADIO_2057_VCOBUF_TUNE, ci2->RF_vcobuf_tune); ++ write_radio_reg(pi, ++ RADIO_2057_LOGEN_MX2G_TUNE, ++ ci2->RF_logen_mx2g_tune); ++ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE, ++ ci2->RF_logen_indbuf2g_tune); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0, ++ ci2->RF_txmix2g_tune_boost_pu_core0); ++ write_radio_reg(pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE0, ++ ci2->RF_pad2g_tune_pus_core0); ++ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0, ++ ci2->RF_lna2g_tune_core0); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1, ++ ci2->RF_txmix2g_tune_boost_pu_core1); ++ write_radio_reg(pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE1, ++ ci2->RF_pad2g_tune_pus_core1); ++ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1, ++ ci2->RF_lna2g_tune_core1); ++ ++ } else { ++ ++ write_radio_reg(pi, ++ RADIO_2057_VCOCAL_COUNTVAL0, ++ ci->RF_vcocal_countval0); ++ write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1, ++ ci->RF_vcocal_countval1); ++ write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE, ++ ci->RF_rfpll_refmaster_sparextalsize); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ ci->RF_rfpll_loopfilter_r1); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ ci->RF_rfpll_loopfilter_c2); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ ci->RF_rfpll_loopfilter_c1); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, ci->RF_cp_kpd_idac); ++ write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci->RF_rfpll_mmd0); ++ write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci->RF_rfpll_mmd1); ++ write_radio_reg(pi, RADIO_2057_VCOBUF_TUNE, ci->RF_vcobuf_tune); ++ write_radio_reg(pi, ++ RADIO_2057_LOGEN_MX2G_TUNE, ++ ci->RF_logen_mx2g_tune); ++ write_radio_reg(pi, RADIO_2057_LOGEN_MX5G_TUNE, ++ ci->RF_logen_mx5g_tune); ++ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE, ++ ci->RF_logen_indbuf2g_tune); ++ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF5G_TUNE, ++ ci->RF_logen_indbuf5g_tune); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0, ++ ci->RF_txmix2g_tune_boost_pu_core0); ++ write_radio_reg(pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE0, ++ ci->RF_pad2g_tune_pus_core0); ++ write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE0, ++ ci->RF_pga_boost_tune_core0); ++ write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0, ++ ci->RF_txmix5g_boost_tune_core0); ++ write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0, ++ ci->RF_pad5g_tune_misc_pus_core0); ++ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0, ++ ci->RF_lna2g_tune_core0); ++ write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE0, ++ ci->RF_lna5g_tune_core0); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1, ++ ci->RF_txmix2g_tune_boost_pu_core1); ++ write_radio_reg(pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE1, ++ ci->RF_pad2g_tune_pus_core1); ++ write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE1, ++ ci->RF_pga_boost_tune_core1); ++ write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1, ++ ci->RF_txmix5g_boost_tune_core1); ++ write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1, ++ ci->RF_pad5g_tune_misc_pus_core1); ++ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1, ++ ci->RF_lna2g_tune_core1); ++ write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE1, ++ ci->RF_lna5g_tune_core1); ++ } ++ ++ if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) { ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ 0x3f); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ 0x8); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ 0x8); ++ } else { ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ 0x1f); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ 0x8); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ 0x8); ++ } ++ } else if ((pi->pubpi.radiorev == 5) || (pi->pubpi.radiorev == 7) || ++ (pi->pubpi.radiorev == 8)) { ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ 0x1b); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x30); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ 0xa); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ 0xa); ++ } else { ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, ++ 0x1f); ++ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, ++ 0x8); ++ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, ++ 0x8); ++ } ++ ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (PHY_IPA(pi)) { ++ if (pi->pubpi.radiorev == 3) ++ txmix2g_tune_boost_pu = 0x6b; ++ ++ if (pi->pubpi.radiorev == 5) ++ pad2g_tune_pus = 0x73; ++ ++ } else { ++ if (pi->pubpi.radiorev != 5) { ++ pad2g_tune_pus = 0x3; ++ ++ txmix2g_tune_boost_pu = 0x61; ++ } ++ } ++ ++ for (coreNum = 0; coreNum <= 1; coreNum++) { ++ ++ if (txmix2g_tune_boost_pu != 0) ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, ++ TXMIX2G_TUNE_BOOST_PU, ++ txmix2g_tune_boost_pu); ++ ++ if (pad2g_tune_pus != 0) ++ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, ++ PAD2G_TUNE_PUS, ++ pad2g_tune_pus); ++ } ++ } ++ ++ udelay(50); ++ ++ wlc_phy_radio205x_vcocal_nphy(pi); ++} ++ ++static void ++wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, ++ const struct nphy_sfo_cfg *ci) ++{ ++ u16 val; ++ ++ val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; ++ if (CHSPEC_IS5G(chanspec) && !val) { ++ ++ val = R_REG(&pi->regs->psm_phy_hdr_param); ++ W_REG(&pi->regs->psm_phy_hdr_param, ++ (val | MAC_PHY_FORCE_CLK)); ++ ++ or_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), ++ (BBCFG_RESETCCA | BBCFG_RESETRX)); ++ ++ W_REG(&pi->regs->psm_phy_hdr_param, val); ++ ++ or_phy_reg(pi, 0x09, NPHY_BandControl_currentBand); ++ } else if (!CHSPEC_IS5G(chanspec) && val) { ++ ++ and_phy_reg(pi, 0x09, ~NPHY_BandControl_currentBand); ++ ++ val = R_REG(&pi->regs->psm_phy_hdr_param); ++ W_REG(&pi->regs->psm_phy_hdr_param, ++ (val | MAC_PHY_FORCE_CLK)); ++ ++ and_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), ++ (u16) (~(BBCFG_RESETCCA | BBCFG_RESETRX))); ++ ++ W_REG(&pi->regs->psm_phy_hdr_param, val); ++ } ++ ++ write_phy_reg(pi, 0x1ce, ci->PHY_BW1a); ++ write_phy_reg(pi, 0x1cf, ci->PHY_BW2); ++ write_phy_reg(pi, 0x1d0, ci->PHY_BW3); ++ ++ write_phy_reg(pi, 0x1d1, ci->PHY_BW4); ++ write_phy_reg(pi, 0x1d2, ci->PHY_BW5); ++ write_phy_reg(pi, 0x1d3, ci->PHY_BW6); ++ ++ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { ++ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en, 0); ++ ++ or_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, 0x800); ++ } else { ++ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en, ++ NPHY_ClassifierCtrl_ofdm_en); ++ ++ if (CHSPEC_IS2G(chanspec)) ++ and_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, ~0x840); ++ } ++ ++ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) ++ wlc_phy_txpwr_fixpower_nphy(pi); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ wlc_phy_adjust_lnagaintbl_nphy(pi); ++ ++ wlc_phy_txlpfbw_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3) ++ && (pi->phy_spuravoid != SPURAVOID_DISABLE)) { ++ u8 spuravoid = 0; ++ ++ val = CHSPEC_CHANNEL(chanspec); ++ if (!CHSPEC_IS40(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if ((val == 13) || (val == 14) || (val == 153)) ++ spuravoid = 1; ++ } else if (((val >= 5) && (val <= 8)) || (val == 13) ++ || (val == 14)) { ++ spuravoid = 1; ++ } ++ } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (val == 54) ++ spuravoid = 1; ++ } else { ++ if (pi->nphy_aband_spurwar_en && ++ ((val == 38) || (val == 102) ++ || (val == 118))) ++ spuravoid = 1; ++ } ++ ++ if (pi->phy_spuravoid == SPURAVOID_FORCEON) ++ spuravoid = 1; ++ ++ wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); ++ si_pmu_spuravoid(pi->sh->sih, spuravoid); ++ wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); ++ ++ if ((pi->sh->chip == BCM43224_CHIP_ID) || ++ (pi->sh->chip == BCM43225_CHIP_ID)) { ++ ++ if (spuravoid == 1) { ++ ++ W_REG(&pi->regs->tsf_clk_frac_l, ++ 0x5341); ++ W_REG(&pi->regs->tsf_clk_frac_h, ++ 0x8); ++ } else { ++ ++ W_REG(&pi->regs->tsf_clk_frac_l, ++ 0x8889); ++ W_REG(&pi->regs->tsf_clk_frac_h, ++ 0x8); ++ } ++ } ++ ++ wlapi_bmac_core_phypll_reset(pi->sh->physhim); ++ ++ mod_phy_reg(pi, 0x01, (0x1 << 15), ++ ((spuravoid > 0) ? (0x1 << 15) : 0)); ++ ++ wlc_phy_resetcca_nphy(pi); ++ ++ pi->phy_isspuravoid = (spuravoid > 0); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) ++ write_phy_reg(pi, 0x17e, 0x3830); ++ ++ wlc_phy_spurwar_nphy(pi); ++} ++ ++void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec) ++{ ++ int freq; ++ const struct chan_info_nphy_radio2057 *t0 = NULL; ++ const struct chan_info_nphy_radio205x *t1 = NULL; ++ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL; ++ const struct chan_info_nphy_2055 *t3 = NULL; ++ ++ if (!wlc_phy_chan2freq_nphy ++ (pi, CHSPEC_CHANNEL(chanspec), &freq, &t0, &t1, &t2, &t3)) ++ return; ++ ++ wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); ++ ++ if (CHSPEC_BW(chanspec) != pi->bw) ++ wlapi_bmac_bw_set(pi->sh->physhim, CHSPEC_BW(chanspec)); ++ ++ if (CHSPEC_IS40(chanspec)) { ++ if (CHSPEC_SB_UPPER(chanspec)) { ++ or_phy_reg(pi, 0xa0, BPHY_BAND_SEL_UP20); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ or_phy_reg(pi, 0x310, PRIM_SEL_UP20); ++ } else { ++ and_phy_reg(pi, 0xa0, ~BPHY_BAND_SEL_UP20); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ and_phy_reg(pi, 0x310, ++ (~PRIM_SEL_UP20 & 0xffff)); ++ } ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ if ((pi->pubpi.radiorev <= 4) ++ || (pi->pubpi.radiorev == 6)) { ++ mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE0, ++ 0x2, ++ (CHSPEC_IS5G(chanspec) ? (1 << 1) ++ : 0)); ++ mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE1, ++ 0x2, ++ (CHSPEC_IS5G(chanspec) ? (1 << 1) ++ : 0)); ++ } ++ ++ wlc_phy_chanspec_radio2057_setup(pi, t0, t2); ++ wlc_phy_chanspec_nphy_setup(pi, chanspec, ++ (pi->pubpi.radiorev == 5) ? ++ (const struct nphy_sfo_cfg *)&(t2->PHY_BW1a) : ++ (const struct nphy_sfo_cfg *)&(t0->PHY_BW1a)); ++ ++ } else { ++ ++ mod_radio_reg(pi, ++ RADIO_2056_SYN_COM_CTRL | RADIO_2056_SYN, ++ 0x4, ++ (CHSPEC_IS5G(chanspec) ? (0x1 << 2) : 0)); ++ wlc_phy_chanspec_radio2056_setup(pi, t1); ++ ++ wlc_phy_chanspec_nphy_setup(pi, chanspec, ++ (const struct nphy_sfo_cfg *) &(t1->PHY_BW1a)); ++ } ++ ++ } else { ++ ++ mod_radio_reg(pi, RADIO_2055_MASTER_CNTRL1, 0x70, ++ (CHSPEC_IS5G(chanspec) ? (0x02 << 4) ++ : (0x05 << 4))); ++ ++ wlc_phy_chanspec_radio2055_setup(pi, t3); ++ wlc_phy_chanspec_nphy_setup(pi, chanspec, ++ (const struct nphy_sfo_cfg *) ++ &(t3->PHY_BW1a)); ++ } ++ ++} ++ ++void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) ++{ ++ struct brcms_phy *pi = (struct brcms_phy *) ppi; ++ u16 mask = 0xfc00; ++ u32 mc = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ return; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ u16 v0 = 0x211, v1 = 0x222, v2 = 0x144, v3 = 0x188; ++ ++ if (lut_init == false) ++ return; ++ ++ if (pi->srom_fem2g.antswctrllut == 0) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x02, 16, &v0); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x03, 16, &v1); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x08, 16, &v2); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x0C, 16, &v3); ++ } ++ ++ if (pi->srom_fem5g.antswctrllut == 0) { ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x12, 16, &v0); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x13, 16, &v1); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x18, 16, &v2); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, ++ 1, 0x1C, 16, &v3); ++ } ++ } else { ++ ++ write_phy_reg(pi, 0xc8, 0x0); ++ write_phy_reg(pi, 0xc9, 0x0); ++ ++ ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY); ++ ++ mc = R_REG(&pi->regs->maccontrol); ++ mc &= ~MCTL_GPOUT_SEL_MASK; ++ W_REG(&pi->regs->maccontrol, mc); ++ ++ OR_REG(&pi->regs->psm_gpio_oe, mask); ++ ++ AND_REG(&pi->regs->psm_gpio_out, ~mask); ++ ++ if (lut_init) { ++ write_phy_reg(pi, 0xf8, 0x02d8); ++ write_phy_reg(pi, 0xf9, 0x0301); ++ write_phy_reg(pi, 0xfa, 0x02d8); ++ write_phy_reg(pi, 0xfb, 0x0301); ++ } ++ } ++} ++ ++u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val) ++{ ++ u16 curr_ctl, new_ctl; ++ bool suspended = false; ++ ++ if (D11REV_IS(pi->sh->corerev, 16)) { ++ suspended = ++ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ? ++ false : true; ++ if (!suspended) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ } ++ ++ curr_ctl = read_phy_reg(pi, 0xb0) & (0x7 << 0); ++ ++ new_ctl = (curr_ctl & (~mask)) | (val & mask); ++ ++ mod_phy_reg(pi, 0xb0, (0x7 << 0), new_ctl); ++ ++ if (D11REV_IS(pi->sh->corerev, 16) && !suspended) ++ wlapi_enable_mac(pi->sh->physhim); ++ ++ return new_ctl; ++} ++ ++void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd) ++{ ++ u16 trigger_mask, status_mask; ++ u16 orig_RfseqCoreActv; ++ ++ switch (cmd) { ++ case NPHY_RFSEQ_RX2TX: ++ trigger_mask = NPHY_RfseqTrigger_rx2tx; ++ status_mask = NPHY_RfseqStatus_rx2tx; ++ break; ++ case NPHY_RFSEQ_TX2RX: ++ trigger_mask = NPHY_RfseqTrigger_tx2rx; ++ status_mask = NPHY_RfseqStatus_tx2rx; ++ break; ++ case NPHY_RFSEQ_RESET2RX: ++ trigger_mask = NPHY_RfseqTrigger_reset2rx; ++ status_mask = NPHY_RfseqStatus_reset2rx; ++ break; ++ case NPHY_RFSEQ_UPDATEGAINH: ++ trigger_mask = NPHY_RfseqTrigger_updategainh; ++ status_mask = NPHY_RfseqStatus_updategainh; ++ break; ++ case NPHY_RFSEQ_UPDATEGAINL: ++ trigger_mask = NPHY_RfseqTrigger_updategainl; ++ status_mask = NPHY_RfseqStatus_updategainl; ++ break; ++ case NPHY_RFSEQ_UPDATEGAINU: ++ trigger_mask = NPHY_RfseqTrigger_updategainu; ++ status_mask = NPHY_RfseqStatus_updategainu; ++ break; ++ default: ++ return; ++ } ++ ++ orig_RfseqCoreActv = read_phy_reg(pi, 0xa1); ++ or_phy_reg(pi, 0xa1, ++ (NPHY_RfseqMode_CoreActv_override | ++ NPHY_RfseqMode_Trigger_override)); ++ or_phy_reg(pi, 0xa3, trigger_mask); ++ SPINWAIT((read_phy_reg(pi, 0xa4) & status_mask), 200000); ++ write_phy_reg(pi, 0xa1, orig_RfseqCoreActv); ++ WARN(read_phy_reg(pi, 0xa4) & status_mask, "HW error in rf"); ++} ++ ++static void ++wlc_phy_rfctrl_override_1tomany_nphy(struct brcms_phy *pi, u16 cmd, u16 value, ++ u8 core_mask, u8 off) ++{ ++ u16 rfmxgain = 0, lpfgain = 0; ++ u16 tgain = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ switch (cmd) { ++ case NPHY_REV7_RfctrlOverride_cmd_rxrf_pu: ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 5), ++ value, core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 4), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 3), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ break; ++ case NPHY_REV7_RfctrlOverride_cmd_rx_pu: ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), ++ value, core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 1), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 0), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 1), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 11), 0, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ break; ++ case NPHY_REV7_RfctrlOverride_cmd_tx_pu: ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), ++ value, core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 1), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 0), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), value, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 11), 1, ++ core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ break; ++ case NPHY_REV7_RfctrlOverride_cmd_rxgain: ++ rfmxgain = value & 0x000ff; ++ lpfgain = value & 0x0ff00; ++ lpfgain = lpfgain >> 8; ++ ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 11), ++ rfmxgain, core_mask, ++ off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x3 << 13), ++ lpfgain, core_mask, ++ off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ break; ++ case NPHY_REV7_RfctrlOverride_cmd_txgain: ++ tgain = value & 0x7fff; ++ lpfgain = value & 0x8000; ++ lpfgain = lpfgain >> 14; ++ ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 12), ++ tgain, core_mask, off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 13), ++ lpfgain, core_mask, ++ off, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ break; ++ } ++ } ++} ++ ++static void ++wlc_phy_scale_offset_rssi_nphy(struct brcms_phy *pi, u16 scale, s8 offset, ++ u8 coresel, u8 rail, u8 rssi_type) ++{ ++ u16 valuetostuff; ++ ++ offset = (offset > NPHY_RSSICAL_MAXREAD) ? ++ NPHY_RSSICAL_MAXREAD : offset; ++ offset = (offset < (-NPHY_RSSICAL_MAXREAD - 1)) ? ++ -NPHY_RSSICAL_MAXREAD - 1 : offset; ++ ++ valuetostuff = ((scale & 0x3f) << 8) | (offset & 0x3f); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) ++ write_phy_reg(pi, 0x1a6, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) ++ write_phy_reg(pi, 0x1ac, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) ++ write_phy_reg(pi, 0x1b2, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) ++ write_phy_reg(pi, 0x1b8, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) ++ write_phy_reg(pi, 0x1a4, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) ++ write_phy_reg(pi, 0x1aa, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) ++ write_phy_reg(pi, 0x1b0, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) ++ write_phy_reg(pi, 0x1b6, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) ++ write_phy_reg(pi, 0x1a5, valuetostuff); ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) ++ write_phy_reg(pi, 0x1ab, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) ++ write_phy_reg(pi, 0x1b1, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) ++ write_phy_reg(pi, 0x1b7, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) ++ write_phy_reg(pi, 0x1a7, valuetostuff); ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) ++ write_phy_reg(pi, 0x1ad, valuetostuff); ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) ++ write_phy_reg(pi, 0x1b3, valuetostuff); ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) ++ write_phy_reg(pi, 0x1b9, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) ++ write_phy_reg(pi, 0x1a8, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) ++ write_phy_reg(pi, 0x1ae, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) ++ write_phy_reg(pi, 0x1b4, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) ++ write_phy_reg(pi, 0x1ba, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) ++ write_phy_reg(pi, 0x1a9, valuetostuff); ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) ++ write_phy_reg(pi, 0x1b5, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE1) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) ++ write_phy_reg(pi, 0x1af, valuetostuff); ++ ++ if (((coresel == RADIO_MIMO_CORESEL_CORE2) || ++ (coresel == RADIO_MIMO_CORESEL_ALLRX)) && ++ (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) ++ write_phy_reg(pi, 0x1bb, valuetostuff); ++} ++ ++static void brcms_phy_wr_tx_mux(struct brcms_phy *pi, u8 core) ++{ ++ if (PHY_IPA(pi)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ write_radio_reg(pi, ++ ((core == PHY_CORE_0) ? ++ RADIO_2057_TX0_TX_SSI_MUX : ++ RADIO_2057_TX1_TX_SSI_MUX), ++ (CHSPEC_IS5G(pi->radio_chanspec) ? ++ 0xc : 0xe)); ++ else ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MUX | ++ ((core == PHY_CORE_0) ? ++ RADIO_2056_TX0 : RADIO_2056_TX1), ++ (CHSPEC_IS5G(pi->radio_chanspec) ? ++ 0xc : 0xe)); ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ write_radio_reg(pi, ++ ((core == PHY_CORE_0) ? ++ RADIO_2057_TX0_TX_SSI_MUX : ++ RADIO_2057_TX1_TX_SSI_MUX), ++ 0x11); ++ ++ if (pi->pubpi.radioid == BCM2057_ID) ++ write_radio_reg(pi, ++ RADIO_2057_IQTEST_SEL_PU, 0x1); ++ ++ } else { ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MUX | ++ ((core == PHY_CORE_0) ? ++ RADIO_2056_TX0 : RADIO_2056_TX1), ++ 0x11); ++ } ++ } ++} ++ ++void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type) ++{ ++ u16 mask, val; ++ u16 afectrlovr_rssi_val, rfctrlcmd_rxen_val, rfctrlcmd_coresel_val, ++ startseq; ++ u16 rfctrlovr_rssi_val, rfctrlovr_rxen_val, rfctrlovr_coresel_val, ++ rfctrlovr_trigger_val; ++ u16 afectrlovr_rssi_mask, rfctrlcmd_mask, rfctrlovr_mask; ++ u16 rfctrlcmd_val, rfctrlovr_val; ++ u8 core; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (core_code == RADIO_MIMO_CORESEL_OFF) { ++ mod_phy_reg(pi, 0x8f, (0x1 << 9), 0); ++ mod_phy_reg(pi, 0xa5, (0x1 << 9), 0); ++ ++ mod_phy_reg(pi, 0xa6, (0x3 << 8), 0); ++ mod_phy_reg(pi, 0xa7, (0x3 << 8), 0); ++ ++ mod_phy_reg(pi, 0xe5, (0x1 << 5), 0); ++ mod_phy_reg(pi, 0xe6, (0x1 << 5), 0); ++ ++ mask = (0x1 << 2) | ++ (0x1 << 3) | (0x1 << 4) | (0x1 << 5); ++ mod_phy_reg(pi, 0xf9, mask, 0); ++ mod_phy_reg(pi, 0xfb, mask, 0); ++ ++ } else { ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ if (core_code == RADIO_MIMO_CORESEL_CORE1 ++ && core == PHY_CORE_1) ++ continue; ++ else if (core_code == RADIO_MIMO_CORESEL_CORE2 ++ && core == PHY_CORE_0) ++ continue; ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0x8f : 0xa5, (0x1 << 9), 1 << 9); ++ ++ if (rssi_type == NPHY_RSSI_SEL_W1 || ++ rssi_type == NPHY_RSSI_SEL_W2 || ++ rssi_type == NPHY_RSSI_SEL_NB) { ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 : 0xa7, ++ (0x3 << 8), 0); ++ ++ mask = (0x1 << 2) | ++ (0x1 << 3) | ++ (0x1 << 4) | (0x1 << 5); ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xf9 : 0xfb, ++ mask, 0); ++ ++ if (rssi_type == NPHY_RSSI_SEL_W1) { ++ if (CHSPEC_IS5G( ++ pi->radio_chanspec)) { ++ mask = (0x1 << 2); ++ val = 1 << 2; ++ } else { ++ mask = (0x1 << 3); ++ val = 1 << 3; ++ } ++ } else if (rssi_type == ++ NPHY_RSSI_SEL_W2) { ++ mask = (0x1 << 4); ++ val = 1 << 4; ++ } else { ++ mask = (0x1 << 5); ++ val = 1 << 5; ++ } ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xf9 : 0xfb, ++ mask, val); ++ ++ mask = (0x1 << 5); ++ val = 1 << 5; ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xe5 : 0xe6, mask, val); ++ } else { ++ if (rssi_type == NPHY_RSSI_SEL_TBD) { ++ mask = (0x3 << 8); ++ val = 1 << 8; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ mask = (0x3 << 10); ++ val = 1 << 10; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ } else if (rssi_type == ++ NPHY_RSSI_SEL_IQ) { ++ mask = (0x3 << 8); ++ val = 2 << 8; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ mask = (0x3 << 10); ++ val = 2 << 10; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ } else { ++ mask = (0x3 << 8); ++ val = 3 << 8; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ mask = (0x3 << 10); ++ val = 3 << 10; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0xa6 ++ : 0xa7, mask, val); ++ brcms_phy_wr_tx_mux(pi, core); ++ afectrlovr_rssi_val = 1 << 9; ++ mod_phy_reg(pi, ++ (core == ++ PHY_CORE_0) ? 0x8f ++ : 0xa5, (0x1 << 9), ++ afectrlovr_rssi_val); ++ } ++ } ++ } ++ } ++ } else { ++ ++ if ((rssi_type == NPHY_RSSI_SEL_W1) || ++ (rssi_type == NPHY_RSSI_SEL_W2) || ++ (rssi_type == NPHY_RSSI_SEL_NB)) ++ val = 0x0; ++ else if (rssi_type == NPHY_RSSI_SEL_TBD) ++ val = 0x1; ++ else if (rssi_type == NPHY_RSSI_SEL_IQ) ++ val = 0x2; ++ else ++ val = 0x3; ++ ++ mask = ((0x3 << 12) | (0x3 << 14)); ++ val = (val << 12) | (val << 14); ++ mod_phy_reg(pi, 0xa6, mask, val); ++ mod_phy_reg(pi, 0xa7, mask, val); ++ ++ if ((rssi_type == NPHY_RSSI_SEL_W1) || ++ (rssi_type == NPHY_RSSI_SEL_W2) || ++ (rssi_type == NPHY_RSSI_SEL_NB)) { ++ if (rssi_type == NPHY_RSSI_SEL_W1) ++ val = 0x1; ++ if (rssi_type == NPHY_RSSI_SEL_W2) ++ val = 0x2; ++ if (rssi_type == NPHY_RSSI_SEL_NB) ++ val = 0x3; ++ ++ mask = (0x3 << 4); ++ val = (val << 4); ++ mod_phy_reg(pi, 0x7a, mask, val); ++ mod_phy_reg(pi, 0x7d, mask, val); ++ } ++ ++ if (core_code == RADIO_MIMO_CORESEL_OFF) { ++ afectrlovr_rssi_val = 0; ++ rfctrlcmd_rxen_val = 0; ++ rfctrlcmd_coresel_val = 0; ++ rfctrlovr_rssi_val = 0; ++ rfctrlovr_rxen_val = 0; ++ rfctrlovr_coresel_val = 0; ++ rfctrlovr_trigger_val = 0; ++ startseq = 0; ++ } else { ++ afectrlovr_rssi_val = 1; ++ rfctrlcmd_rxen_val = 1; ++ rfctrlcmd_coresel_val = core_code; ++ rfctrlovr_rssi_val = 1; ++ rfctrlovr_rxen_val = 1; ++ rfctrlovr_coresel_val = 1; ++ rfctrlovr_trigger_val = 1; ++ startseq = 1; ++ } ++ ++ afectrlovr_rssi_mask = ((0x1 << 12) | (0x1 << 13)); ++ afectrlovr_rssi_val = (afectrlovr_rssi_val << ++ 12) | (afectrlovr_rssi_val << 13); ++ mod_phy_reg(pi, 0xa5, afectrlovr_rssi_mask, ++ afectrlovr_rssi_val); ++ ++ if ((rssi_type == NPHY_RSSI_SEL_W1) || ++ (rssi_type == NPHY_RSSI_SEL_W2) || ++ (rssi_type == NPHY_RSSI_SEL_NB)) { ++ rfctrlcmd_mask = ((0x1 << 8) | (0x7 << 3)); ++ rfctrlcmd_val = (rfctrlcmd_rxen_val << 8) | ++ (rfctrlcmd_coresel_val << 3); ++ ++ rfctrlovr_mask = ((0x1 << 5) | ++ (0x1 << 12) | ++ (0x1 << 1) | (0x1 << 0)); ++ rfctrlovr_val = (rfctrlovr_rssi_val << ++ 5) | ++ (rfctrlovr_rxen_val << 12) | ++ (rfctrlovr_coresel_val << 1) | ++ (rfctrlovr_trigger_val << 0); ++ ++ mod_phy_reg(pi, 0x78, rfctrlcmd_mask, rfctrlcmd_val); ++ mod_phy_reg(pi, 0xec, rfctrlovr_mask, rfctrlovr_val); ++ ++ mod_phy_reg(pi, 0x78, (0x1 << 0), (startseq << 0)); ++ udelay(20); ++ ++ mod_phy_reg(pi, 0xec, (0x1 << 0), 0); ++ } ++ } ++} ++ ++int ++wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf, ++ u8 nsamps) ++{ ++ s16 rssi0, rssi1; ++ u16 afectrlCore1_save = 0; ++ u16 afectrlCore2_save = 0; ++ u16 afectrlOverride1_save = 0; ++ u16 afectrlOverride2_save = 0; ++ u16 rfctrlOverrideAux0_save = 0; ++ u16 rfctrlOverrideAux1_save = 0; ++ u16 rfctrlMiscReg1_save = 0; ++ u16 rfctrlMiscReg2_save = 0; ++ u16 rfctrlcmd_save = 0; ++ u16 rfctrloverride_save = 0; ++ u16 rfctrlrssiothers1_save = 0; ++ u16 rfctrlrssiothers2_save = 0; ++ s8 tmp_buf[4]; ++ u8 ctr = 0, samp = 0; ++ s32 rssi_out_val; ++ u16 gpiosel_orig; ++ ++ afectrlCore1_save = read_phy_reg(pi, 0xa6); ++ afectrlCore2_save = read_phy_reg(pi, 0xa7); ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ rfctrlMiscReg1_save = read_phy_reg(pi, 0xf9); ++ rfctrlMiscReg2_save = read_phy_reg(pi, 0xfb); ++ afectrlOverride1_save = read_phy_reg(pi, 0x8f); ++ afectrlOverride2_save = read_phy_reg(pi, 0xa5); ++ rfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5); ++ rfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6); ++ } else { ++ afectrlOverride1_save = read_phy_reg(pi, 0xa5); ++ rfctrlcmd_save = read_phy_reg(pi, 0x78); ++ rfctrloverride_save = read_phy_reg(pi, 0xec); ++ rfctrlrssiothers1_save = read_phy_reg(pi, 0x7a); ++ rfctrlrssiothers2_save = read_phy_reg(pi, 0x7d); ++ } ++ ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type); ++ ++ gpiosel_orig = read_phy_reg(pi, 0xca); ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ write_phy_reg(pi, 0xca, 5); ++ ++ for (ctr = 0; ctr < 4; ctr++) ++ rssi_buf[ctr] = 0; ++ ++ for (samp = 0; samp < nsamps; samp++) { ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ rssi0 = read_phy_reg(pi, 0x1c9); ++ rssi1 = read_phy_reg(pi, 0x1ca); ++ } else { ++ rssi0 = read_phy_reg(pi, 0x219); ++ rssi1 = read_phy_reg(pi, 0x21a); ++ } ++ ++ ctr = 0; ++ tmp_buf[ctr++] = ((s8) ((rssi0 & 0x3f) << 2)) >> 2; ++ tmp_buf[ctr++] = ((s8) (((rssi0 >> 8) & 0x3f) << 2)) >> 2; ++ tmp_buf[ctr++] = ((s8) ((rssi1 & 0x3f) << 2)) >> 2; ++ tmp_buf[ctr++] = ((s8) (((rssi1 >> 8) & 0x3f) << 2)) >> 2; ++ ++ for (ctr = 0; ctr < 4; ctr++) ++ rssi_buf[ctr] += tmp_buf[ctr]; ++ ++ } ++ ++ rssi_out_val = rssi_buf[3] & 0xff; ++ rssi_out_val |= (rssi_buf[2] & 0xff) << 8; ++ rssi_out_val |= (rssi_buf[1] & 0xff) << 16; ++ rssi_out_val |= (rssi_buf[0] & 0xff) << 24; ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ write_phy_reg(pi, 0xca, gpiosel_orig); ++ ++ write_phy_reg(pi, 0xa6, afectrlCore1_save); ++ write_phy_reg(pi, 0xa7, afectrlCore2_save); ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0xf9, rfctrlMiscReg1_save); ++ write_phy_reg(pi, 0xfb, rfctrlMiscReg2_save); ++ write_phy_reg(pi, 0x8f, afectrlOverride1_save); ++ write_phy_reg(pi, 0xa5, afectrlOverride2_save); ++ write_phy_reg(pi, 0xe5, rfctrlOverrideAux0_save); ++ write_phy_reg(pi, 0xe6, rfctrlOverrideAux1_save); ++ } else { ++ write_phy_reg(pi, 0xa5, afectrlOverride1_save); ++ write_phy_reg(pi, 0x78, rfctrlcmd_save); ++ write_phy_reg(pi, 0xec, rfctrloverride_save); ++ write_phy_reg(pi, 0x7a, rfctrlrssiothers1_save); ++ write_phy_reg(pi, 0x7d, rfctrlrssiothers2_save); ++ } ++ ++ return rssi_out_val; ++} ++ ++s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi) ++{ ++ u16 core1_txrf_iqcal1_save, core1_txrf_iqcal2_save; ++ u16 core2_txrf_iqcal1_save, core2_txrf_iqcal2_save; ++ u16 pwrdet_rxtx_core1_save; ++ u16 pwrdet_rxtx_core2_save; ++ u16 afectrlCore1_save; ++ u16 afectrlCore2_save; ++ u16 afectrlOverride_save; ++ u16 afectrlOverride2_save; ++ u16 pd_pll_ts_save; ++ u16 gpioSel_save; ++ s32 radio_temp[4]; ++ s32 radio_temp2[4]; ++ u16 syn_tempprocsense_save; ++ s16 offset = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ u16 auxADC_Vmid, auxADC_Av, auxADC_Vmid_save, auxADC_Av_save; ++ u16 auxADC_rssi_ctrlL_save, auxADC_rssi_ctrlH_save; ++ u16 auxADC_rssi_ctrlL, auxADC_rssi_ctrlH; ++ s32 auxADC_Vl; ++ u16 RfctrlOverride5_save, RfctrlOverride6_save; ++ u16 RfctrlMiscReg5_save, RfctrlMiscReg6_save; ++ u16 RSSIMultCoef0QPowerDet_save; ++ u16 tempsense_Rcal; ++ ++ syn_tempprocsense_save = ++ read_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG); ++ ++ afectrlCore1_save = read_phy_reg(pi, 0xa6); ++ afectrlCore2_save = read_phy_reg(pi, 0xa7); ++ afectrlOverride_save = read_phy_reg(pi, 0x8f); ++ afectrlOverride2_save = read_phy_reg(pi, 0xa5); ++ RSSIMultCoef0QPowerDet_save = read_phy_reg(pi, 0x1ae); ++ RfctrlOverride5_save = read_phy_reg(pi, 0x346); ++ RfctrlOverride6_save = read_phy_reg(pi, 0x347); ++ RfctrlMiscReg5_save = read_phy_reg(pi, 0x344); ++ RfctrlMiscReg6_save = read_phy_reg(pi, 0x345); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, ++ &auxADC_Vmid_save); ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, ++ &auxADC_Av_save); ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, ++ &auxADC_rssi_ctrlL_save); ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, ++ &auxADC_rssi_ctrlH_save); ++ ++ write_phy_reg(pi, 0x1ae, 0x0); ++ ++ auxADC_rssi_ctrlL = 0x0; ++ auxADC_rssi_ctrlH = 0x20; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, ++ &auxADC_rssi_ctrlL); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, ++ &auxADC_rssi_ctrlH); ++ ++ tempsense_Rcal = syn_tempprocsense_save & 0x1c; ++ ++ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, ++ tempsense_Rcal | 0x01); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), ++ 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ mod_phy_reg(pi, 0xa6, (0x1 << 7), 0); ++ mod_phy_reg(pi, 0xa7, (0x1 << 7), 0); ++ mod_phy_reg(pi, 0x8f, (0x1 << 7), (0x1 << 7)); ++ mod_phy_reg(pi, 0xa5, (0x1 << 7), (0x1 << 7)); ++ ++ mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2)); ++ udelay(5); ++ mod_phy_reg(pi, 0xa6, (0x1 << 2), 0); ++ mod_phy_reg(pi, 0xa7, (0x1 << 2), 0); ++ mod_phy_reg(pi, 0xa6, (0x1 << 3), 0); ++ mod_phy_reg(pi, 0xa7, (0x1 << 3), 0); ++ mod_phy_reg(pi, 0x8f, (0x1 << 3), (0x1 << 3)); ++ mod_phy_reg(pi, 0xa5, (0x1 << 3), (0x1 << 3)); ++ mod_phy_reg(pi, 0xa6, (0x1 << 6), 0); ++ mod_phy_reg(pi, 0xa7, (0x1 << 6), 0); ++ mod_phy_reg(pi, 0x8f, (0x1 << 6), (0x1 << 6)); ++ mod_phy_reg(pi, 0xa5, (0x1 << 6), (0x1 << 6)); ++ ++ auxADC_Vmid = 0xA3; ++ auxADC_Av = 0x0; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, ++ &auxADC_Vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, ++ &auxADC_Av); ++ ++ udelay(3); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); ++ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, ++ tempsense_Rcal | 0x03); ++ ++ udelay(5); ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); ++ ++ auxADC_Av = 0x7; ++ if (radio_temp[1] + radio_temp2[1] < -30) { ++ auxADC_Vmid = 0x45; ++ auxADC_Vl = 263; ++ } else if (radio_temp[1] + radio_temp2[1] < -9) { ++ auxADC_Vmid = 0x200; ++ auxADC_Vl = 467; ++ } else if (radio_temp[1] + radio_temp2[1] < 11) { ++ auxADC_Vmid = 0x266; ++ auxADC_Vl = 634; ++ } else { ++ auxADC_Vmid = 0x2D5; ++ auxADC_Vl = 816; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, ++ &auxADC_Vmid); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, ++ &auxADC_Av); ++ ++ udelay(3); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); ++ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, ++ tempsense_Rcal | 0x01); ++ ++ udelay(5); ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); ++ ++ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, ++ syn_tempprocsense_save); ++ ++ write_phy_reg(pi, 0xa6, afectrlCore1_save); ++ write_phy_reg(pi, 0xa7, afectrlCore2_save); ++ write_phy_reg(pi, 0x8f, afectrlOverride_save); ++ write_phy_reg(pi, 0xa5, afectrlOverride2_save); ++ write_phy_reg(pi, 0x1ae, RSSIMultCoef0QPowerDet_save); ++ write_phy_reg(pi, 0x346, RfctrlOverride5_save); ++ write_phy_reg(pi, 0x347, RfctrlOverride6_save); ++ write_phy_reg(pi, 0x344, RfctrlMiscReg5_save); ++ write_phy_reg(pi, 0x345, RfctrlMiscReg5_save); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, ++ &auxADC_Vmid_save); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, ++ &auxADC_Av_save); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, ++ &auxADC_rssi_ctrlL_save); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, ++ &auxADC_rssi_ctrlH_save); ++ ++ radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) ++ + 82 * (auxADC_Vl) - 28861 + ++ 128) / 256; ++ ++ offset = (s16) pi->phy_tempsense_offset; ++ ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ syn_tempprocsense_save = ++ read_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE); ++ ++ afectrlCore1_save = read_phy_reg(pi, 0xa6); ++ afectrlCore2_save = read_phy_reg(pi, 0xa7); ++ afectrlOverride_save = read_phy_reg(pi, 0x8f); ++ afectrlOverride2_save = read_phy_reg(pi, 0xa5); ++ gpioSel_save = read_phy_reg(pi, 0xca); ++ ++ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) ++ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x05); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x01); ++ else ++ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01); ++ ++ radio_temp[0] = ++ (126 * (radio_temp[1] + radio_temp2[1]) + 3987) / 64; ++ ++ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, ++ syn_tempprocsense_save); ++ ++ write_phy_reg(pi, 0xca, gpioSel_save); ++ write_phy_reg(pi, 0xa6, afectrlCore1_save); ++ write_phy_reg(pi, 0xa7, afectrlCore2_save); ++ write_phy_reg(pi, 0x8f, afectrlOverride_save); ++ write_phy_reg(pi, 0xa5, afectrlOverride2_save); ++ ++ offset = (s16) pi->phy_tempsense_offset; ++ } else { ++ ++ pwrdet_rxtx_core1_save = ++ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1); ++ pwrdet_rxtx_core2_save = ++ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2); ++ core1_txrf_iqcal1_save = ++ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1); ++ core1_txrf_iqcal2_save = ++ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2); ++ core2_txrf_iqcal1_save = ++ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1); ++ core2_txrf_iqcal2_save = ++ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2); ++ pd_pll_ts_save = read_radio_reg(pi, RADIO_2055_PD_PLL_TS); ++ ++ afectrlCore1_save = read_phy_reg(pi, 0xa6); ++ afectrlCore2_save = read_phy_reg(pi, 0xa7); ++ afectrlOverride_save = read_phy_reg(pi, 0xa5); ++ gpioSel_save = read_phy_reg(pi, 0xca); ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x01); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x01); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x08); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x08); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04); ++ write_radio_reg(pi, RADIO_2055_PD_PLL_TS, 0x00); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); ++ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); ++ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); ++ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); ++ ++ radio_temp[0] = (radio_temp[0] + radio_temp2[0]); ++ radio_temp[1] = (radio_temp[1] + radio_temp2[1]); ++ radio_temp[2] = (radio_temp[2] + radio_temp2[2]); ++ radio_temp[3] = (radio_temp[3] + radio_temp2[3]); ++ ++ radio_temp[0] = ++ (radio_temp[0] + radio_temp[1] + radio_temp[2] + ++ radio_temp[3]); ++ ++ radio_temp[0] = ++ (radio_temp[0] + ++ (8 * 32)) * (950 - 350) / 63 + (350 * 8); ++ ++ radio_temp[0] = (radio_temp[0] - (8 * 420)) / 38; ++ ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, ++ pwrdet_rxtx_core1_save); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, ++ pwrdet_rxtx_core2_save); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, ++ core1_txrf_iqcal1_save); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, ++ core2_txrf_iqcal1_save); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, ++ core1_txrf_iqcal2_save); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, ++ core2_txrf_iqcal2_save); ++ write_radio_reg(pi, RADIO_2055_PD_PLL_TS, pd_pll_ts_save); ++ ++ write_phy_reg(pi, 0xca, gpioSel_save); ++ write_phy_reg(pi, 0xa6, afectrlCore1_save); ++ write_phy_reg(pi, 0xa7, afectrlCore2_save); ++ write_phy_reg(pi, 0xa5, afectrlOverride_save); ++ } ++ ++ return (s16) radio_temp[0] + offset; ++} ++ ++static void ++wlc_phy_set_rssi_2055_vcm(struct brcms_phy *pi, u8 rssi_type, u8 *vcm_buf) ++{ ++ u8 core; ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ if (rssi_type == NPHY_RSSI_SEL_NB) { ++ if (core == PHY_CORE_0) { ++ mod_radio_reg(pi, ++ RADIO_2055_CORE1_B0_NBRSSI_VCM, ++ RADIO_2055_NBRSSI_VCM_I_MASK, ++ vcm_buf[2 * ++ core] << ++ RADIO_2055_NBRSSI_VCM_I_SHIFT); ++ mod_radio_reg(pi, ++ RADIO_2055_CORE1_RXBB_RSSI_CTRL5, ++ RADIO_2055_NBRSSI_VCM_Q_MASK, ++ vcm_buf[2 * core + ++ 1] << ++ RADIO_2055_NBRSSI_VCM_Q_SHIFT); ++ } else { ++ mod_radio_reg(pi, ++ RADIO_2055_CORE2_B0_NBRSSI_VCM, ++ RADIO_2055_NBRSSI_VCM_I_MASK, ++ vcm_buf[2 * ++ core] << ++ RADIO_2055_NBRSSI_VCM_I_SHIFT); ++ mod_radio_reg(pi, ++ RADIO_2055_CORE2_RXBB_RSSI_CTRL5, ++ RADIO_2055_NBRSSI_VCM_Q_MASK, ++ vcm_buf[2 * core + ++ 1] << ++ RADIO_2055_NBRSSI_VCM_Q_SHIFT); ++ } ++ } else { ++ if (core == PHY_CORE_0) ++ mod_radio_reg(pi, ++ RADIO_2055_CORE1_RXBB_RSSI_CTRL5, ++ RADIO_2055_WBRSSI_VCM_IQ_MASK, ++ vcm_buf[2 * ++ core] << ++ RADIO_2055_WBRSSI_VCM_IQ_SHIFT); ++ else ++ mod_radio_reg(pi, ++ RADIO_2055_CORE2_RXBB_RSSI_CTRL5, ++ RADIO_2055_WBRSSI_VCM_IQ_MASK, ++ vcm_buf[2 * ++ core] << ++ RADIO_2055_WBRSSI_VCM_IQ_SHIFT); ++ } ++ } ++} ++ ++static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi) ++{ ++ u16 classif_state; ++ u16 clip_state[2]; ++ u16 clip_off[] = { 0xffff, 0xffff }; ++ s32 target_code; ++ u8 vcm, min_vcm; ++ u8 vcm_final = 0; ++ u8 result_idx; ++ s32 poll_results[8][4] = { ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0} ++ }; ++ s32 poll_result_core[4] = { 0, 0, 0, 0 }; ++ s32 min_d = NPHY_RSSICAL_MAXD, curr_d; ++ s32 fine_digital_offset[4]; ++ s32 poll_results_min[4] = { 0, 0, 0, 0 }; ++ s32 min_poll; ++ u8 vcm_level_max; ++ u8 core; ++ u8 wb_cnt; ++ u8 rssi_type; ++ u16 NPHY_Rfctrlintc1_save, NPHY_Rfctrlintc2_save; ++ u16 NPHY_AfectrlOverride1_save, NPHY_AfectrlOverride2_save; ++ u16 NPHY_AfectrlCore1_save, NPHY_AfectrlCore2_save; ++ u16 NPHY_RfctrlOverride0_save, NPHY_RfctrlOverride1_save; ++ u16 NPHY_RfctrlOverrideAux0_save, NPHY_RfctrlOverrideAux1_save; ++ u16 NPHY_RfctrlCmd_save; ++ u16 NPHY_RfctrlMiscReg1_save, NPHY_RfctrlMiscReg2_save; ++ u16 NPHY_RfctrlRSSIOTHERS1_save, NPHY_RfctrlRSSIOTHERS2_save; ++ u8 rxcore_state; ++ u16 NPHY_REV7_RfctrlOverride3_save, NPHY_REV7_RfctrlOverride4_save; ++ u16 NPHY_REV7_RfctrlOverride5_save, NPHY_REV7_RfctrlOverride6_save; ++ u16 NPHY_REV7_RfctrlMiscReg3_save, NPHY_REV7_RfctrlMiscReg4_save; ++ u16 NPHY_REV7_RfctrlMiscReg5_save, NPHY_REV7_RfctrlMiscReg6_save; ++ ++ NPHY_REV7_RfctrlOverride3_save = ++ NPHY_REV7_RfctrlOverride4_save = ++ NPHY_REV7_RfctrlOverride5_save = ++ NPHY_REV7_RfctrlOverride6_save = ++ NPHY_REV7_RfctrlMiscReg3_save = ++ NPHY_REV7_RfctrlMiscReg4_save = ++ NPHY_REV7_RfctrlMiscReg5_save = ++ NPHY_REV7_RfctrlMiscReg6_save = 0; ++ ++ classif_state = wlc_phy_classifier_nphy(pi, 0, 0); ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); ++ wlc_phy_clip_det_nphy(pi, 0, clip_state); ++ wlc_phy_clip_det_nphy(pi, 1, clip_off); ++ ++ NPHY_Rfctrlintc1_save = read_phy_reg(pi, 0x91); ++ NPHY_Rfctrlintc2_save = read_phy_reg(pi, 0x92); ++ NPHY_AfectrlOverride1_save = read_phy_reg(pi, 0x8f); ++ NPHY_AfectrlOverride2_save = read_phy_reg(pi, 0xa5); ++ NPHY_AfectrlCore1_save = read_phy_reg(pi, 0xa6); ++ NPHY_AfectrlCore2_save = read_phy_reg(pi, 0xa7); ++ NPHY_RfctrlOverride0_save = read_phy_reg(pi, 0xe7); ++ NPHY_RfctrlOverride1_save = read_phy_reg(pi, 0xec); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ NPHY_REV7_RfctrlOverride3_save = read_phy_reg(pi, 0x342); ++ NPHY_REV7_RfctrlOverride4_save = read_phy_reg(pi, 0x343); ++ NPHY_REV7_RfctrlOverride5_save = read_phy_reg(pi, 0x346); ++ NPHY_REV7_RfctrlOverride6_save = read_phy_reg(pi, 0x347); ++ } ++ NPHY_RfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5); ++ NPHY_RfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6); ++ NPHY_RfctrlCmd_save = read_phy_reg(pi, 0x78); ++ NPHY_RfctrlMiscReg1_save = read_phy_reg(pi, 0xf9); ++ NPHY_RfctrlMiscReg2_save = read_phy_reg(pi, 0xfb); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ NPHY_REV7_RfctrlMiscReg3_save = read_phy_reg(pi, 0x340); ++ NPHY_REV7_RfctrlMiscReg4_save = read_phy_reg(pi, 0x341); ++ NPHY_REV7_RfctrlMiscReg5_save = read_phy_reg(pi, 0x344); ++ NPHY_REV7_RfctrlMiscReg6_save = read_phy_reg(pi, 0x345); ++ } ++ NPHY_RfctrlRSSIOTHERS1_save = read_phy_reg(pi, 0x7a); ++ NPHY_RfctrlRSSIOTHERS2_save = read_phy_reg(pi, 0x7d); ++ ++ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_OFF, 0, ++ RADIO_MIMO_CORESEL_ALLRXTX); ++ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_TRSW, 1, ++ RADIO_MIMO_CORESEL_ALLRXTX); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_rxrf_pu, ++ 0, 0, 0); ++ else ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0, 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_rx_pu, ++ 1, 0, 0); ++ else ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0, 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), ++ 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 6), 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 7), 1, 0, 0); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 6), 1, 0, 0); ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 5), ++ 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 4), 1, 0, ++ 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 0, 0, 0); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 1, 0, 0); ++ } ++ ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 4), ++ 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 5), 1, 0, ++ 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 0, 0, 0); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 1, 0, 0); ++ } ++ } ++ ++ rxcore_state = wlc_phy_rxcore_getstate_nphy( ++ (struct brcms_phy_pub *) pi); ++ ++ vcm_level_max = 8; ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ if ((rxcore_state & (1 << core)) == 0) ++ continue; ++ ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, ++ core == ++ PHY_CORE_0 ? ++ RADIO_MIMO_CORESEL_CORE1 : ++ RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RAIL_I, NPHY_RSSI_SEL_NB); ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, ++ core == ++ PHY_CORE_0 ? ++ RADIO_MIMO_CORESEL_CORE1 : ++ RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RAIL_Q, NPHY_RSSI_SEL_NB); ++ ++ for (vcm = 0; vcm < vcm_level_max; vcm++) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ mod_radio_reg(pi, (core == PHY_CORE_0) ? ++ RADIO_2057_NB_MASTER_CORE0 : ++ RADIO_2057_NB_MASTER_CORE1, ++ RADIO_2057_VCM_MASK, vcm); ++ else ++ mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC | ++ ((core == ++ PHY_CORE_0) ? RADIO_2056_RX0 : ++ RADIO_2056_RX1), ++ RADIO_2056_VCM_MASK, ++ vcm << RADIO_2056_RSSI_VCM_SHIFT); ++ ++ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_NB, ++ &poll_results[vcm][0], ++ NPHY_RSSICAL_NPOLL); ++ } ++ ++ for (result_idx = 0; result_idx < 4; result_idx++) { ++ if ((core == result_idx / 2) && ++ (result_idx % 2 == 0)) { ++ ++ min_d = NPHY_RSSICAL_MAXD; ++ min_vcm = 0; ++ min_poll = ++ NPHY_RSSICAL_MAXREAD * ++ NPHY_RSSICAL_NPOLL + 1; ++ for (vcm = 0; vcm < vcm_level_max; vcm++) { ++ curr_d = ++ poll_results[vcm][result_idx] * ++ poll_results[vcm][result_idx] + ++ poll_results[vcm][result_idx + ++ 1] * ++ poll_results[vcm][result_idx + ++ 1]; ++ if (curr_d < min_d) { ++ min_d = curr_d; ++ min_vcm = vcm; ++ } ++ if (poll_results[vcm][result_idx] < ++ min_poll) ++ min_poll = ++ poll_results[vcm] ++ [result_idx]; ++ } ++ vcm_final = min_vcm; ++ poll_results_min[result_idx] = min_poll; ++ } ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ mod_radio_reg(pi, (core == PHY_CORE_0) ? ++ RADIO_2057_NB_MASTER_CORE0 : ++ RADIO_2057_NB_MASTER_CORE1, ++ RADIO_2057_VCM_MASK, vcm_final); ++ else ++ mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC | ++ ((core == ++ PHY_CORE_0) ? RADIO_2056_RX0 : ++ RADIO_2056_RX1), RADIO_2056_VCM_MASK, ++ vcm_final << RADIO_2056_RSSI_VCM_SHIFT); ++ ++ for (result_idx = 0; result_idx < 4; result_idx++) { ++ if (core == result_idx / 2) { ++ fine_digital_offset[result_idx] = ++ (NPHY_RSSICAL_NB_TARGET * ++ NPHY_RSSICAL_NPOLL) - ++ poll_results[vcm_final][result_idx]; ++ if (fine_digital_offset[result_idx] < 0) { ++ fine_digital_offset[result_idx] = ++ abs(fine_digital_offset ++ [result_idx]); ++ fine_digital_offset[result_idx] += ++ (NPHY_RSSICAL_NPOLL / 2); ++ fine_digital_offset[result_idx] /= ++ NPHY_RSSICAL_NPOLL; ++ fine_digital_offset[result_idx] = ++ -fine_digital_offset[ ++ result_idx]; ++ } else { ++ fine_digital_offset[result_idx] += ++ (NPHY_RSSICAL_NPOLL / 2); ++ fine_digital_offset[result_idx] /= ++ NPHY_RSSICAL_NPOLL; ++ } ++ ++ if (poll_results_min[result_idx] == ++ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) ++ fine_digital_offset[result_idx] = ++ (NPHY_RSSICAL_NB_TARGET - ++ NPHY_RSSICAL_MAXREAD - 1); ++ ++ wlc_phy_scale_offset_rssi_nphy( ++ pi, 0x0, ++ (s8) ++ fine_digital_offset ++ [result_idx], ++ (result_idx / 2 == 0) ? ++ RADIO_MIMO_CORESEL_CORE1 : ++ RADIO_MIMO_CORESEL_CORE2, ++ (result_idx % 2 == 0) ? ++ NPHY_RAIL_I : NPHY_RAIL_Q, ++ NPHY_RSSI_SEL_NB); ++ } ++ } ++ ++ } ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ if ((rxcore_state & (1 << core)) == 0) ++ continue; ++ ++ for (wb_cnt = 0; wb_cnt < 2; wb_cnt++) { ++ if (wb_cnt == 0) { ++ rssi_type = NPHY_RSSI_SEL_W1; ++ target_code = NPHY_RSSICAL_W1_TARGET_REV3; ++ } else { ++ rssi_type = NPHY_RSSI_SEL_W2; ++ target_code = NPHY_RSSICAL_W2_TARGET_REV3; ++ } ++ ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, ++ core == ++ PHY_CORE_0 ? ++ RADIO_MIMO_CORESEL_CORE1 ++ : ++ RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RAIL_I, rssi_type); ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, ++ core == ++ PHY_CORE_0 ? ++ RADIO_MIMO_CORESEL_CORE1 ++ : ++ RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RAIL_Q, rssi_type); ++ ++ wlc_phy_poll_rssi_nphy(pi, rssi_type, poll_result_core, ++ NPHY_RSSICAL_NPOLL); ++ ++ for (result_idx = 0; result_idx < 4; result_idx++) { ++ if (core == result_idx / 2) { ++ fine_digital_offset[result_idx] = ++ (target_code * ++ NPHY_RSSICAL_NPOLL) - ++ poll_result_core[result_idx]; ++ if (fine_digital_offset[result_idx] < ++ 0) { ++ fine_digital_offset[result_idx] ++ = abs( ++ fine_digital_offset ++ [result_idx]); ++ fine_digital_offset[result_idx] ++ += (NPHY_RSSICAL_NPOLL ++ / 2); ++ fine_digital_offset[result_idx] ++ /= NPHY_RSSICAL_NPOLL; ++ fine_digital_offset[result_idx] ++ = -fine_digital_offset ++ [result_idx]; ++ } else { ++ fine_digital_offset[result_idx] ++ += (NPHY_RSSICAL_NPOLL ++ / 2); ++ fine_digital_offset[result_idx] ++ /= NPHY_RSSICAL_NPOLL; ++ } ++ ++ wlc_phy_scale_offset_rssi_nphy( ++ pi, 0x0, ++ (s8) ++ fine_digital_offset ++ [core * ++ 2], ++ (core == PHY_CORE_0) ? ++ RADIO_MIMO_CORESEL_CORE1 : ++ RADIO_MIMO_CORESEL_CORE2, ++ (result_idx % 2 == 0) ? ++ NPHY_RAIL_I : ++ NPHY_RAIL_Q, ++ rssi_type); ++ } ++ } ++ ++ } ++ } ++ ++ write_phy_reg(pi, 0x91, NPHY_Rfctrlintc1_save); ++ write_phy_reg(pi, 0x92, NPHY_Rfctrlintc2_save); ++ ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ ++ mod_phy_reg(pi, 0xe7, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x78, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0xe7, (0x1 << 0), 0); ++ ++ mod_phy_reg(pi, 0xec, (0x1 << 0), 1 << 0); ++ mod_phy_reg(pi, 0x78, (0x1 << 1), 1 << 1); ++ mod_phy_reg(pi, 0xec, (0x1 << 0), 0); ++ ++ write_phy_reg(pi, 0x8f, NPHY_AfectrlOverride1_save); ++ write_phy_reg(pi, 0xa5, NPHY_AfectrlOverride2_save); ++ write_phy_reg(pi, 0xa6, NPHY_AfectrlCore1_save); ++ write_phy_reg(pi, 0xa7, NPHY_AfectrlCore2_save); ++ write_phy_reg(pi, 0xe7, NPHY_RfctrlOverride0_save); ++ write_phy_reg(pi, 0xec, NPHY_RfctrlOverride1_save); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ write_phy_reg(pi, 0x342, NPHY_REV7_RfctrlOverride3_save); ++ write_phy_reg(pi, 0x343, NPHY_REV7_RfctrlOverride4_save); ++ write_phy_reg(pi, 0x346, NPHY_REV7_RfctrlOverride5_save); ++ write_phy_reg(pi, 0x347, NPHY_REV7_RfctrlOverride6_save); ++ } ++ write_phy_reg(pi, 0xe5, NPHY_RfctrlOverrideAux0_save); ++ write_phy_reg(pi, 0xe6, NPHY_RfctrlOverrideAux1_save); ++ write_phy_reg(pi, 0x78, NPHY_RfctrlCmd_save); ++ write_phy_reg(pi, 0xf9, NPHY_RfctrlMiscReg1_save); ++ write_phy_reg(pi, 0xfb, NPHY_RfctrlMiscReg2_save); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ write_phy_reg(pi, 0x340, NPHY_REV7_RfctrlMiscReg3_save); ++ write_phy_reg(pi, 0x341, NPHY_REV7_RfctrlMiscReg4_save); ++ write_phy_reg(pi, 0x344, NPHY_REV7_RfctrlMiscReg5_save); ++ write_phy_reg(pi, 0x345, NPHY_REV7_RfctrlMiscReg6_save); ++ } ++ write_phy_reg(pi, 0x7a, NPHY_RfctrlRSSIOTHERS1_save); ++ write_phy_reg(pi, 0x7d, NPHY_RfctrlRSSIOTHERS2_save); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ pi->rssical_cache.rssical_radio_regs_2G[0] = ++ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0); ++ pi->rssical_cache.rssical_radio_regs_2G[1] = ++ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1); ++ } else { ++ pi->rssical_cache.rssical_radio_regs_2G[0] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | ++ RADIO_2056_RX0); ++ pi->rssical_cache.rssical_radio_regs_2G[1] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | ++ RADIO_2056_RX1); ++ } ++ ++ pi->rssical_cache.rssical_phyregs_2G[0] = ++ read_phy_reg(pi, 0x1a6); ++ pi->rssical_cache.rssical_phyregs_2G[1] = ++ read_phy_reg(pi, 0x1ac); ++ pi->rssical_cache.rssical_phyregs_2G[2] = ++ read_phy_reg(pi, 0x1b2); ++ pi->rssical_cache.rssical_phyregs_2G[3] = ++ read_phy_reg(pi, 0x1b8); ++ pi->rssical_cache.rssical_phyregs_2G[4] = ++ read_phy_reg(pi, 0x1a4); ++ pi->rssical_cache.rssical_phyregs_2G[5] = ++ read_phy_reg(pi, 0x1aa); ++ pi->rssical_cache.rssical_phyregs_2G[6] = ++ read_phy_reg(pi, 0x1b0); ++ pi->rssical_cache.rssical_phyregs_2G[7] = ++ read_phy_reg(pi, 0x1b6); ++ pi->rssical_cache.rssical_phyregs_2G[8] = ++ read_phy_reg(pi, 0x1a5); ++ pi->rssical_cache.rssical_phyregs_2G[9] = ++ read_phy_reg(pi, 0x1ab); ++ pi->rssical_cache.rssical_phyregs_2G[10] = ++ read_phy_reg(pi, 0x1b1); ++ pi->rssical_cache.rssical_phyregs_2G[11] = ++ read_phy_reg(pi, 0x1b7); ++ ++ pi->nphy_rssical_chanspec_2G = pi->radio_chanspec; ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ pi->rssical_cache.rssical_radio_regs_5G[0] = ++ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0); ++ pi->rssical_cache.rssical_radio_regs_5G[1] = ++ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1); ++ } else { ++ pi->rssical_cache.rssical_radio_regs_5G[0] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | ++ RADIO_2056_RX0); ++ pi->rssical_cache.rssical_radio_regs_5G[1] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RSSI_MISC | ++ RADIO_2056_RX1); ++ } ++ ++ pi->rssical_cache.rssical_phyregs_5G[0] = ++ read_phy_reg(pi, 0x1a6); ++ pi->rssical_cache.rssical_phyregs_5G[1] = ++ read_phy_reg(pi, 0x1ac); ++ pi->rssical_cache.rssical_phyregs_5G[2] = ++ read_phy_reg(pi, 0x1b2); ++ pi->rssical_cache.rssical_phyregs_5G[3] = ++ read_phy_reg(pi, 0x1b8); ++ pi->rssical_cache.rssical_phyregs_5G[4] = ++ read_phy_reg(pi, 0x1a4); ++ pi->rssical_cache.rssical_phyregs_5G[5] = ++ read_phy_reg(pi, 0x1aa); ++ pi->rssical_cache.rssical_phyregs_5G[6] = ++ read_phy_reg(pi, 0x1b0); ++ pi->rssical_cache.rssical_phyregs_5G[7] = ++ read_phy_reg(pi, 0x1b6); ++ pi->rssical_cache.rssical_phyregs_5G[8] = ++ read_phy_reg(pi, 0x1a5); ++ pi->rssical_cache.rssical_phyregs_5G[9] = ++ read_phy_reg(pi, 0x1ab); ++ pi->rssical_cache.rssical_phyregs_5G[10] = ++ read_phy_reg(pi, 0x1b1); ++ pi->rssical_cache.rssical_phyregs_5G[11] = ++ read_phy_reg(pi, 0x1b7); ++ ++ pi->nphy_rssical_chanspec_5G = pi->radio_chanspec; ++ } ++ ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); ++ wlc_phy_clip_det_nphy(pi, 1, clip_state); ++} ++ ++static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type) ++{ ++ s32 target_code; ++ u16 classif_state; ++ u16 clip_state[2]; ++ u16 rssi_ctrl_state[2], pd_state[2]; ++ u16 rfctrlintc_state[2], rfpdcorerxtx_state[2]; ++ u16 rfctrlintc_override_val; ++ u16 clip_off[] = { 0xffff, 0xffff }; ++ u16 rf_pd_val, pd_mask, rssi_ctrl_mask; ++ u8 vcm, min_vcm, vcm_tmp[4]; ++ u8 vcm_final[4] = { 0, 0, 0, 0 }; ++ u8 result_idx, ctr; ++ s32 poll_results[4][4] = { ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0}, ++ {0, 0, 0, 0} ++ }; ++ s32 poll_miniq[4][2] = { ++ {0, 0}, ++ {0, 0}, ++ {0, 0}, ++ {0, 0} ++ }; ++ s32 min_d, curr_d; ++ s32 fine_digital_offset[4]; ++ s32 poll_results_min[4] = { 0, 0, 0, 0 }; ++ s32 min_poll; ++ ++ switch (rssi_type) { ++ case NPHY_RSSI_SEL_NB: ++ target_code = NPHY_RSSICAL_NB_TARGET; ++ break; ++ case NPHY_RSSI_SEL_W1: ++ target_code = NPHY_RSSICAL_W1_TARGET; ++ break; ++ case NPHY_RSSI_SEL_W2: ++ target_code = NPHY_RSSICAL_W2_TARGET; ++ break; ++ default: ++ return; ++ break; ++ } ++ ++ classif_state = wlc_phy_classifier_nphy(pi, 0, 0); ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); ++ wlc_phy_clip_det_nphy(pi, 0, clip_state); ++ wlc_phy_clip_det_nphy(pi, 1, clip_off); ++ ++ rf_pd_val = (rssi_type == NPHY_RSSI_SEL_NB) ? 0x6 : 0x4; ++ rfctrlintc_override_val = ++ CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 : 0x110; ++ ++ rfctrlintc_state[0] = read_phy_reg(pi, 0x91); ++ rfpdcorerxtx_state[0] = read_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX); ++ write_phy_reg(pi, 0x91, rfctrlintc_override_val); ++ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rf_pd_val); ++ ++ rfctrlintc_state[1] = read_phy_reg(pi, 0x92); ++ rfpdcorerxtx_state[1] = read_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX); ++ write_phy_reg(pi, 0x92, rfctrlintc_override_val); ++ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rf_pd_val); ++ ++ pd_mask = RADIO_2055_NBRSSI_PD | RADIO_2055_WBRSSI_G1_PD | ++ RADIO_2055_WBRSSI_G2_PD; ++ pd_state[0] = ++ read_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC) & pd_mask; ++ pd_state[1] = ++ read_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC) & pd_mask; ++ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, 0); ++ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, 0); ++ rssi_ctrl_mask = RADIO_2055_NBRSSI_SEL | RADIO_2055_WBRSSI_G1_SEL | ++ RADIO_2055_WBRSSI_G2_SEL; ++ rssi_ctrl_state[0] = ++ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE1) & rssi_ctrl_mask; ++ rssi_ctrl_state[1] = ++ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE2) & rssi_ctrl_mask; ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type); ++ ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX, ++ NPHY_RAIL_I, rssi_type); ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX, ++ NPHY_RAIL_Q, rssi_type); ++ ++ for (vcm = 0; vcm < 4; vcm++) { ++ ++ vcm_tmp[0] = vcm_tmp[1] = vcm_tmp[2] = vcm_tmp[3] = vcm; ++ if (rssi_type != NPHY_RSSI_SEL_W2) ++ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_tmp); ++ ++ wlc_phy_poll_rssi_nphy(pi, rssi_type, &poll_results[vcm][0], ++ NPHY_RSSICAL_NPOLL); ++ ++ if ((rssi_type == NPHY_RSSI_SEL_W1) ++ || (rssi_type == NPHY_RSSI_SEL_W2)) { ++ for (ctr = 0; ctr < 2; ctr++) ++ poll_miniq[vcm][ctr] = ++ min(poll_results[vcm][ctr * 2 + 0], ++ poll_results[vcm][ctr * 2 + 1]); ++ } ++ } ++ ++ for (result_idx = 0; result_idx < 4; result_idx++) { ++ min_d = NPHY_RSSICAL_MAXD; ++ min_vcm = 0; ++ min_poll = NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL + 1; ++ for (vcm = 0; vcm < 4; vcm++) { ++ curr_d = abs(((rssi_type == NPHY_RSSI_SEL_NB) ? ++ poll_results[vcm][result_idx] : ++ poll_miniq[vcm][result_idx / 2]) - ++ (target_code * NPHY_RSSICAL_NPOLL)); ++ if (curr_d < min_d) { ++ min_d = curr_d; ++ min_vcm = vcm; ++ } ++ if (poll_results[vcm][result_idx] < min_poll) ++ min_poll = poll_results[vcm][result_idx]; ++ } ++ vcm_final[result_idx] = min_vcm; ++ poll_results_min[result_idx] = min_poll; ++ } ++ ++ if (rssi_type != NPHY_RSSI_SEL_W2) ++ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_final); ++ ++ for (result_idx = 0; result_idx < 4; result_idx++) { ++ fine_digital_offset[result_idx] = ++ (target_code * NPHY_RSSICAL_NPOLL) - ++ poll_results[vcm_final[result_idx]][result_idx]; ++ if (fine_digital_offset[result_idx] < 0) { ++ fine_digital_offset[result_idx] = ++ abs(fine_digital_offset[result_idx]); ++ fine_digital_offset[result_idx] += ++ (NPHY_RSSICAL_NPOLL / 2); ++ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL; ++ fine_digital_offset[result_idx] = ++ -fine_digital_offset[result_idx]; ++ } else { ++ fine_digital_offset[result_idx] += ++ (NPHY_RSSICAL_NPOLL / 2); ++ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL; ++ } ++ ++ if (poll_results_min[result_idx] == ++ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) ++ fine_digital_offset[result_idx] = ++ (target_code - NPHY_RSSICAL_MAXREAD - 1); ++ ++ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, ++ (s8) ++ fine_digital_offset[result_idx], ++ (result_idx / 2 == ++ 0) ? RADIO_MIMO_CORESEL_CORE1 : ++ RADIO_MIMO_CORESEL_CORE2, ++ (result_idx % 2 == ++ 0) ? NPHY_RAIL_I : NPHY_RAIL_Q, ++ rssi_type); ++ } ++ ++ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, pd_state[0]); ++ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, pd_state[1]); ++ if (rssi_ctrl_state[0] == RADIO_2055_NBRSSI_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, ++ NPHY_RSSI_SEL_NB); ++ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G1_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, ++ NPHY_RSSI_SEL_W1); ++ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G2_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, ++ NPHY_RSSI_SEL_W2); ++ else ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, ++ NPHY_RSSI_SEL_W2); ++ if (rssi_ctrl_state[1] == RADIO_2055_NBRSSI_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RSSI_SEL_NB); ++ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G1_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RSSI_SEL_W1); ++ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G2_SEL) ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RSSI_SEL_W2); ++ else ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, ++ NPHY_RSSI_SEL_W2); ++ ++ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, rssi_type); ++ ++ write_phy_reg(pi, 0x91, rfctrlintc_state[0]); ++ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rfpdcorerxtx_state[0]); ++ write_phy_reg(pi, 0x92, rfctrlintc_state[1]); ++ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rfpdcorerxtx_state[1]); ++ ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); ++ wlc_phy_clip_det_nphy(pi, 1, clip_state); ++ ++ wlc_phy_resetcca_nphy(pi); ++} ++ ++void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi) ++{ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ wlc_phy_rssi_cal_nphy_rev3(pi); ++ } else { ++ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_NB); ++ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W1); ++ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W2); ++ } ++} ++ ++int ++wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh) ++{ ++ s16 rxpwr, rxpwr0, rxpwr1; ++ s16 phyRx0_l, phyRx2_l; ++ ++ rxpwr = 0; ++ rxpwr0 = rxh->PhyRxStatus_1 & PRXS1_nphy_PWR0_MASK; ++ rxpwr1 = (rxh->PhyRxStatus_1 & PRXS1_nphy_PWR1_MASK) >> 8; ++ ++ if (rxpwr0 > 127) ++ rxpwr0 -= 256; ++ if (rxpwr1 > 127) ++ rxpwr1 -= 256; ++ ++ phyRx0_l = rxh->PhyRxStatus_0 & 0x00ff; ++ phyRx2_l = rxh->PhyRxStatus_2 & 0x00ff; ++ if (phyRx2_l > 127) ++ phyRx2_l -= 256; ++ ++ if (((rxpwr0 == 16) || (rxpwr0 == 32))) { ++ rxpwr0 = rxpwr1; ++ rxpwr1 = phyRx2_l; ++ } ++ ++ if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MAX) ++ rxpwr = (rxpwr0 > rxpwr1) ? rxpwr0 : rxpwr1; ++ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MIN) ++ rxpwr = (rxpwr0 < rxpwr1) ? rxpwr0 : rxpwr1; ++ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_AVG) ++ rxpwr = (rxpwr0 + rxpwr1) >> 1; ++ ++ return rxpwr; ++} ++ ++static void ++wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, struct cordic_iq *tone_buf, ++ u16 num_samps) ++{ ++ u16 t; ++ u32 *data_buf = NULL; ++ ++ data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC); ++ if (data_buf == NULL) ++ return; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ for (t = 0; t < num_samps; t++) ++ data_buf[t] = ((((unsigned int)tone_buf[t].i) & 0x3ff) << 10) | ++ (((unsigned int)tone_buf[t].q) & 0x3ff); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SAMPLEPLAY, num_samps, 0, 32, ++ data_buf); ++ ++ kfree(data_buf); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static u16 ++wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, ++ u8 dac_test_mode) ++{ ++ u8 phy_bw, is_phybw40; ++ u16 num_samps, t, spur; ++ s32 theta = 0, rot = 0; ++ u32 tbl_len; ++ struct cordic_iq *tone_buf = NULL; ++ ++ is_phybw40 = CHSPEC_IS40(pi->radio_chanspec); ++ phy_bw = (is_phybw40 == 1) ? 40 : 20; ++ tbl_len = (phy_bw << 3); ++ ++ if (dac_test_mode == 1) { ++ spur = read_phy_reg(pi, 0x01); ++ spur = (spur >> 15) & 1; ++ phy_bw = (spur == 1) ? 82 : 80; ++ phy_bw = (is_phybw40 == 1) ? (phy_bw << 1) : phy_bw; ++ ++ tbl_len = (phy_bw << 1); ++ } ++ ++ tone_buf = kmalloc(sizeof(struct cordic_iq) * tbl_len, GFP_ATOMIC); ++ if (tone_buf == NULL) ++ return 0; ++ ++ num_samps = (u16) tbl_len; ++ rot = ((f_kHz * 36) / phy_bw) / 100; ++ theta = 0; ++ ++ for (t = 0; t < num_samps; t++) { ++ ++ tone_buf[t] = cordic_calc_iq(theta); ++ ++ theta += rot; ++ ++ tone_buf[t].q = (s32) FLOAT(tone_buf[t].q * max_val); ++ tone_buf[t].i = (s32) FLOAT(tone_buf[t].i * max_val); ++ } ++ ++ wlc_phy_loadsampletable_nphy(pi, tone_buf, num_samps); ++ ++ kfree(tone_buf); ++ ++ return num_samps; ++} ++ ++static void ++wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops, ++ u16 wait, u8 iqmode, u8 dac_test_mode, ++ bool modify_bbmult) ++{ ++ u16 bb_mult; ++ u8 phy_bw, sample_cmd; ++ u16 orig_RfseqCoreActv; ++ u16 lpf_bw_ctl_override3, lpf_bw_ctl_override4, lpf_bw_ctl_miscreg3, ++ lpf_bw_ctl_miscreg4; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ phy_bw = 20; ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ phy_bw = 40; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ lpf_bw_ctl_override3 = read_phy_reg(pi, 0x342) & (0x1 << 7); ++ lpf_bw_ctl_override4 = read_phy_reg(pi, 0x343) & (0x1 << 7); ++ if (lpf_bw_ctl_override3 | lpf_bw_ctl_override4) { ++ lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) & ++ (0x7 << 8); ++ lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) & ++ (0x7 << 8); ++ } else { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 7), ++ wlc_phy_read_lpf_bw_ctl_nphy ++ (pi, ++ 0), 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ pi->nphy_sample_play_lpf_bw_ctl_ovr = true; ++ ++ lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) & ++ (0x7 << 8); ++ lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) & ++ (0x7 << 8); ++ } ++ } ++ ++ if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) == 0) { ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, ++ &bb_mult); ++ pi->nphy_bb_mult_save = ++ BB_MULT_VALID_MASK | (bb_mult & BB_MULT_MASK); ++ } ++ ++ if (modify_bbmult) { ++ bb_mult = (phy_bw == 20) ? 100 : 71; ++ bb_mult = (bb_mult << 8) + bb_mult; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, ++ &bb_mult); ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ write_phy_reg(pi, 0xc6, num_samps - 1); ++ ++ if (loops != 0xffff) ++ write_phy_reg(pi, 0xc4, loops - 1); ++ else ++ write_phy_reg(pi, 0xc4, loops); ++ ++ write_phy_reg(pi, 0xc5, wait); ++ ++ orig_RfseqCoreActv = read_phy_reg(pi, 0xa1); ++ or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override); ++ if (iqmode) { ++ ++ and_phy_reg(pi, 0xc2, 0x7FFF); ++ ++ or_phy_reg(pi, 0xc2, 0x8000); ++ } else { ++ ++ sample_cmd = (dac_test_mode == 1) ? 0x5 : 0x1; ++ write_phy_reg(pi, 0xc3, sample_cmd); ++ } ++ ++ SPINWAIT(((read_phy_reg(pi, 0xa4) & 0x1) == 1), 1000); ++ ++ write_phy_reg(pi, 0xa1, orig_RfseqCoreActv); ++} ++ ++int ++wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, ++ u8 iqmode, u8 dac_test_mode, bool modify_bbmult) ++{ ++ u16 num_samps; ++ u16 loops = 0xffff; ++ u16 wait = 0; ++ ++ num_samps = wlc_phy_gen_load_samples_nphy(pi, f_kHz, max_val, ++ dac_test_mode); ++ if (num_samps == 0) ++ return -EBADE; ++ ++ wlc_phy_runsamples_nphy(pi, num_samps, loops, wait, iqmode, ++ dac_test_mode, modify_bbmult); ++ ++ return 0; ++} ++ ++void wlc_phy_stopplayback_nphy(struct brcms_phy *pi) ++{ ++ u16 playback_status; ++ u16 bb_mult; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ playback_status = read_phy_reg(pi, 0xc7); ++ if (playback_status & 0x1) ++ or_phy_reg(pi, 0xc3, NPHY_sampleCmd_STOP); ++ else if (playback_status & 0x2) ++ and_phy_reg(pi, 0xc2, ++ (u16) ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN); ++ ++ and_phy_reg(pi, 0xc3, (u16) ~(0x1 << 2)); ++ ++ if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) != 0) { ++ ++ bb_mult = pi->nphy_bb_mult_save & BB_MULT_MASK; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, ++ &bb_mult); ++ ++ pi->nphy_bb_mult_save = 0; ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7) || NREV_GE(pi->pubpi.phy_rev, 8)) { ++ if (pi->nphy_sample_play_lpf_bw_ctl_ovr) { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 7), ++ 0, 0, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ pi->nphy_sample_play_lpf_bw_ctl_ovr = false; ++ } ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static u32 *brcms_phy_get_tx_pwrctrl_tbl(struct brcms_phy *pi) ++{ ++ u32 *tx_pwrctrl_tbl = NULL; ++ uint phyrev = pi->pubpi.phy_rev; ++ ++ if (PHY_IPA(pi)) { ++ tx_pwrctrl_tbl = ++ wlc_phy_get_ipa_gaintbl_nphy(pi); ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_IS(phyrev, 3)) ++ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev3; ++ else if (NREV_IS(phyrev, 4)) ++ tx_pwrctrl_tbl = ++ (pi->srom_fem5g.extpagain == 3) ? ++ nphy_tpc_5GHz_txgain_HiPwrEPA : ++ nphy_tpc_5GHz_txgain_rev4; ++ else ++ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev5; ++ } else { ++ if (NREV_GE(phyrev, 7)) { ++ if (pi->pubpi.radiorev == 3) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_epa_2057rev3; ++ else if (pi->pubpi.radiorev == 5) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_epa_2057rev5; ++ } else { ++ if (NREV_GE(phyrev, 5) && ++ (pi->srom_fem2g.extpagain == 3)) ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_HiPwrEPA; ++ else ++ tx_pwrctrl_tbl = ++ nphy_tpc_txgain_rev3; ++ } ++ } ++ } ++ return tx_pwrctrl_tbl; ++} ++ ++struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi) ++{ ++ u16 base_idx[2], curr_gain[2]; ++ u8 core_no; ++ struct nphy_txgains target_gain; ++ u32 *tx_pwrctrl_tbl = NULL; ++ ++ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) { ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ curr_gain); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ for (core_no = 0; core_no < 2; core_no++) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ target_gain.ipa[core_no] = ++ curr_gain[core_no] & 0x0007; ++ target_gain.pad[core_no] = ++ ((curr_gain[core_no] & 0x00F8) >> 3); ++ target_gain.pga[core_no] = ++ ((curr_gain[core_no] & 0x0F00) >> 8); ++ target_gain.txgm[core_no] = ++ ((curr_gain[core_no] & 0x7000) >> 12); ++ target_gain.txlpf[core_no] = ++ ((curr_gain[core_no] & 0x8000) >> 15); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ target_gain.ipa[core_no] = ++ curr_gain[core_no] & 0x000F; ++ target_gain.pad[core_no] = ++ ((curr_gain[core_no] & 0x00F0) >> 4); ++ target_gain.pga[core_no] = ++ ((curr_gain[core_no] & 0x0F00) >> 8); ++ target_gain.txgm[core_no] = ++ ((curr_gain[core_no] & 0x7000) >> 12); ++ } else { ++ target_gain.ipa[core_no] = ++ curr_gain[core_no] & 0x0003; ++ target_gain.pad[core_no] = ++ ((curr_gain[core_no] & 0x000C) >> 2); ++ target_gain.pga[core_no] = ++ ((curr_gain[core_no] & 0x0070) >> 4); ++ target_gain.txgm[core_no] = ++ ((curr_gain[core_no] & 0x0380) >> 7); ++ } ++ } ++ } else { ++ uint phyrev = pi->pubpi.phy_rev; ++ ++ base_idx[0] = (read_phy_reg(pi, 0x1ed) >> 8) & 0x7f; ++ base_idx[1] = (read_phy_reg(pi, 0x1ee) >> 8) & 0x7f; ++ for (core_no = 0; core_no < 2; core_no++) { ++ if (NREV_GE(phyrev, 3)) { ++ tx_pwrctrl_tbl = ++ brcms_phy_get_tx_pwrctrl_tbl(pi); ++ if (NREV_GE(phyrev, 7)) { ++ target_gain.ipa[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 16) & 0x7; ++ target_gain.pad[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 19) & 0x1f; ++ target_gain.pga[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 24) & 0xf; ++ target_gain.txgm[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 28) & 0x7; ++ target_gain.txlpf[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 31) & 0x1; ++ } else { ++ target_gain.ipa[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 16) & 0xf; ++ target_gain.pad[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 20) & 0xf; ++ target_gain.pga[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 24) & 0xf; ++ target_gain.txgm[core_no] = ++ (tx_pwrctrl_tbl ++ [base_idx[core_no]] ++ >> 28) & 0x7; ++ } ++ } else { ++ target_gain.ipa[core_no] = ++ (nphy_tpc_txgain[base_idx[core_no]] >> ++ 16) & 0x3; ++ target_gain.pad[core_no] = ++ (nphy_tpc_txgain[base_idx[core_no]] >> ++ 18) & 0x3; ++ target_gain.pga[core_no] = ++ (nphy_tpc_txgain[base_idx[core_no]] >> ++ 20) & 0x7; ++ target_gain.txgm[core_no] = ++ (nphy_tpc_txgain[base_idx[core_no]] >> ++ 23) & 0x7; ++ } ++ } ++ } ++ ++ return target_gain; ++} ++ ++static void ++wlc_phy_iqcal_gainparams_nphy(struct brcms_phy *pi, u16 core_no, ++ struct nphy_txgains target_gain, ++ struct nphy_iqcal_params *params) ++{ ++ u8 k; ++ int idx; ++ u16 gain_index; ++ u8 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ params->txlpf = target_gain.txlpf[core_no]; ++ ++ params->txgm = target_gain.txgm[core_no]; ++ params->pga = target_gain.pga[core_no]; ++ params->pad = target_gain.pad[core_no]; ++ params->ipa = target_gain.ipa[core_no]; ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ params->cal_gain = ++ ((params->txlpf << 15) | (params->txgm << 12) | ++ (params->pga << 8) | ++ (params->pad << 3) | (params->ipa)); ++ else ++ params->cal_gain = ++ ((params->txgm << 12) | (params->pga << 8) | ++ (params->pad << 4) | (params->ipa)); ++ ++ params->ncorr[0] = 0x79; ++ params->ncorr[1] = 0x79; ++ params->ncorr[2] = 0x79; ++ params->ncorr[3] = 0x79; ++ params->ncorr[4] = 0x79; ++ } else { ++ ++ gain_index = ((target_gain.pad[core_no] << 0) | ++ (target_gain.pga[core_no] << 4) | ++ (target_gain.txgm[core_no] << 8)); ++ ++ idx = -1; ++ for (k = 0; k < NPHY_IQCAL_NUMGAINS; k++) { ++ if (tbl_iqcal_gainparams_nphy[band_idx][k][0] == ++ gain_index) { ++ idx = k; ++ break; ++ } ++ } ++ ++ params->txgm = tbl_iqcal_gainparams_nphy[band_idx][k][1]; ++ params->pga = tbl_iqcal_gainparams_nphy[band_idx][k][2]; ++ params->pad = tbl_iqcal_gainparams_nphy[band_idx][k][3]; ++ params->cal_gain = ((params->txgm << 7) | (params->pga << 4) | ++ (params->pad << 2)); ++ params->ncorr[0] = tbl_iqcal_gainparams_nphy[band_idx][k][4]; ++ params->ncorr[1] = tbl_iqcal_gainparams_nphy[band_idx][k][5]; ++ params->ncorr[2] = tbl_iqcal_gainparams_nphy[band_idx][k][6]; ++ params->ncorr[3] = tbl_iqcal_gainparams_nphy[band_idx][k][7]; ++ } ++} ++ ++static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi) ++{ ++ u16 jtag_core, core; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ for (core = 0; core <= 1; core++) { ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_VCM_HG); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_IDAC); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_VCM); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = 0; ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MUX); ++ ++ if (pi->pubpi.radiorev != 5) ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, ++ core, ++ TSSIA); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_MISC1); ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER, 0x0a); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_VCM_HG, 0x43); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_IDAC, 0x55); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_VCM, 0x00); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSIG, 0x00); ++ if (pi->use_int_tx_iqlo_cal_nphy) { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TX_SSI_MUX, 0x4); ++ if (!(pi-> ++ internal_tx_iqlo_cal_tapoff_intpa_nphy)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIA, 0x31); ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIA, 0x21); ++ } ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_MISC1, 0x00); ++ } else { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER, 0x06); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_VCM_HG, 0x43); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ IQCAL_IDAC, 0x55); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_VCM, 0x00); ++ ++ if (pi->pubpi.radiorev != 5) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TSSIA, 0x00); ++ if (pi->use_int_tx_iqlo_cal_nphy) { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, ++ core, TX_SSI_MUX, ++ 0x06); ++ if (!(pi-> ++ internal_tx_iqlo_cal_tapoff_intpa_nphy)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIG, 0x31); ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, ++ TX, core, ++ TSSIG, 0x21); ++ } ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSI_MISC1, 0x00); ++ } ++ } ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ for (core = 0; core <= 1; core++) { ++ jtag_core = ++ (core == ++ PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1; ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MASTER | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_VCM_HG | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_IDAC | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_TX_TSSI_VCM | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TX_AMP_DET | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MUX | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TSSIA | jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TSSIG | jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC1 | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 9] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC2 | ++ jtag_core); ++ ++ pi->tx_rx_cal_radio_saveregs[(core * 11) + 10] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC3 | ++ jtag_core); ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MASTER | ++ jtag_core, 0x0a); ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_VCM_HG | ++ jtag_core, 0x40); ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_IDAC | ++ jtag_core, 0x55); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_VCM | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_AMP_DET | ++ jtag_core, 0x00); ++ ++ if (PHY_IPA(pi)) { ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TX_SSI_MUX ++ | jtag_core, 0x4); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSIA | ++ jtag_core, 0x1); ++ } else { ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TX_SSI_MUX ++ | jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSIA | ++ jtag_core, 0x2f); ++ } ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSIG | jtag_core, ++ 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC1 | ++ jtag_core, 0x00); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC2 | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC3 | ++ jtag_core, 0x00); ++ } else { ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MASTER | ++ jtag_core, 0x06); ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_VCM_HG | ++ jtag_core, 0x40); ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_IDAC | ++ jtag_core, 0x55); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_VCM | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_AMP_DET | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSIA | jtag_core, ++ 0x00); ++ ++ if (PHY_IPA(pi)) { ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TX_SSI_MUX ++ | jtag_core, 0x06); ++ if (NREV_LT(pi->pubpi.phy_rev, 5)) ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TSSIG ++ | jtag_core, ++ 0x11); ++ else ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TSSIG ++ | jtag_core, ++ 0x1); ++ } else { ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TX_SSI_MUX ++ | jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSIG | ++ jtag_core, 0x20); ++ } ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC1 | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC2 | ++ jtag_core, 0x00); ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC3 | ++ jtag_core, 0x00); ++ } ++ } ++ } else { ++ ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x29); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x54); ++ ++ pi->tx_rx_cal_radio_saveregs[2] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x29); ++ pi->tx_rx_cal_radio_saveregs[3] = ++ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x54); ++ ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1); ++ pi->tx_rx_cal_radio_saveregs[5] = ++ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2); ++ ++ if ((read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand) == ++ 0) { ++ ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04); ++ } else { ++ ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x20); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x20); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ ++ or_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0x20); ++ or_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0x20); ++ } else { ++ ++ and_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0xdf); ++ and_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0xdf); ++ } ++ } ++} ++ ++static void wlc_phy_txcal_radio_cleanup_nphy(struct brcms_phy *pi) ++{ ++ u16 jtag_core, core; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ for (core = 0; core <= 1; core++) { ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TX_SSI_MASTER, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 0]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 1]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 2]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 3]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TX_SSI_MUX, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 5]); ++ ++ if (pi->pubpi.radiorev != 5) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TSSIA, ++ pi->tx_rx_cal_radio_saveregs ++ [(core * 11) + 6]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 7]); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 8]); ++ } ++ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ for (core = 0; core <= 1; core++) { ++ jtag_core = (core == PHY_CORE_0) ? ++ RADIO_2056_TX0 : RADIO_2056_TX1; ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MASTER | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 0]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_VCM_HG | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 1]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_IQCAL_IDAC | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 2]); ++ ++ write_radio_reg(pi, RADIO_2056_TX_TSSI_VCM | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 3]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_AMP_DET | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 4]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TX_SSI_MUX | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 5]); ++ ++ write_radio_reg(pi, RADIO_2056_TX_TSSIA | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 6]); ++ ++ write_radio_reg(pi, RADIO_2056_TX_TSSIG | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 7]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC1 | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 8]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC2 | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 9]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TSSI_MISC3 | jtag_core, ++ pi-> ++ tx_rx_cal_radio_saveregs[(core * 11) + ++ 10]); ++ } ++ } else { ++ ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, ++ pi->tx_rx_cal_radio_saveregs[0]); ++ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, ++ pi->tx_rx_cal_radio_saveregs[1]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, ++ pi->tx_rx_cal_radio_saveregs[2]); ++ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, ++ pi->tx_rx_cal_radio_saveregs[3]); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, ++ pi->tx_rx_cal_radio_saveregs[4]); ++ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, ++ pi->tx_rx_cal_radio_saveregs[5]); ++ } ++} ++ ++static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi) ++{ ++ u16 val, mask; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6); ++ pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7); ++ ++ mask = ((0x3 << 8) | (0x3 << 10)); ++ val = (0x2 << 8); ++ val |= (0x2 << 10); ++ mod_phy_reg(pi, 0xa6, mask, val); ++ mod_phy_reg(pi, 0xa7, mask, val); ++ ++ val = read_phy_reg(pi, 0x8f); ++ pi->tx_rx_cal_phy_saveregs[2] = val; ++ val |= ((0x1 << 9) | (0x1 << 10)); ++ write_phy_reg(pi, 0x8f, val); ++ ++ val = read_phy_reg(pi, 0xa5); ++ pi->tx_rx_cal_phy_saveregs[3] = val; ++ val |= ((0x1 << 9) | (0x1 << 10)); ++ write_phy_reg(pi, 0xa5, val); ++ ++ pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x01); ++ mod_phy_reg(pi, 0x01, (0x1 << 15), 0); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, ++ &val); ++ pi->tx_rx_cal_phy_saveregs[5] = val; ++ val = 0; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, ++ &val); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, ++ &val); ++ pi->tx_rx_cal_phy_saveregs[6] = val; ++ val = 0; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, ++ &val); ++ ++ pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0x91); ++ pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0x92); ++ ++ if (!(pi->use_int_tx_iqlo_cal_nphy)) ++ wlc_phy_rfctrlintc_override_nphy( ++ pi, ++ NPHY_RfctrlIntc_override_PA, ++ 1, ++ RADIO_MIMO_CORESEL_CORE1 ++ | ++ RADIO_MIMO_CORESEL_CORE2); ++ else ++ wlc_phy_rfctrlintc_override_nphy( ++ pi, ++ NPHY_RfctrlIntc_override_PA, ++ 0, ++ RADIO_MIMO_CORESEL_CORE1 ++ | ++ RADIO_MIMO_CORESEL_CORE2); ++ ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x2, RADIO_MIMO_CORESEL_CORE1); ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x8, RADIO_MIMO_CORESEL_CORE2); ++ ++ pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297); ++ pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b); ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7) ++ || NREV_GE(pi->pubpi.phy_rev, 8)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 7), ++ wlc_phy_read_lpf_bw_ctl_nphy ++ (pi, ++ 0), 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ if (pi->use_int_tx_iqlo_cal_nphy ++ && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) { ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7)) { ++ ++ mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4, ++ 1 << 4); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ mod_radio_reg( ++ pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE0, ++ 1, 0); ++ mod_radio_reg( ++ pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE1, ++ 1, 0); ++ } else { ++ mod_radio_reg( ++ pi, ++ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0, ++ 1, 0); ++ mod_radio_reg( ++ pi, ++ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1, ++ 1, 0); ++ } ++ } else if (NREV_GE(pi->pubpi.phy_rev, 8)) { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 3), 0, ++ 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ } ++ } ++ } else { ++ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6); ++ pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7); ++ ++ mask = ((0x3 << 12) | (0x3 << 14)); ++ val = (0x2 << 12); ++ val |= (0x2 << 14); ++ mod_phy_reg(pi, 0xa6, mask, val); ++ mod_phy_reg(pi, 0xa7, mask, val); ++ ++ val = read_phy_reg(pi, 0xa5); ++ pi->tx_rx_cal_phy_saveregs[2] = val; ++ val |= ((0x1 << 12) | (0x1 << 13)); ++ write_phy_reg(pi, 0xa5, val); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, ++ &val); ++ pi->tx_rx_cal_phy_saveregs[3] = val; ++ val |= 0x2000; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, ++ &val); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, ++ &val); ++ pi->tx_rx_cal_phy_saveregs[4] = val; ++ val |= 0x2000; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, ++ &val); ++ ++ pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x91); ++ pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x92); ++ val = CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120; ++ write_phy_reg(pi, 0x91, val); ++ write_phy_reg(pi, 0x92, val); ++ } ++} ++ ++static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi) ++{ ++ u16 mask; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ write_phy_reg(pi, 0xa6, pi->tx_rx_cal_phy_saveregs[0]); ++ write_phy_reg(pi, 0xa7, pi->tx_rx_cal_phy_saveregs[1]); ++ write_phy_reg(pi, 0x8f, pi->tx_rx_cal_phy_saveregs[2]); ++ write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[3]); ++ write_phy_reg(pi, 0x01, pi->tx_rx_cal_phy_saveregs[4]); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, ++ &pi->tx_rx_cal_phy_saveregs[5]); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, ++ &pi->tx_rx_cal_phy_saveregs[6]); ++ ++ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[7]); ++ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[8]); ++ ++ write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]); ++ write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7) ++ || NREV_GE(pi->pubpi.phy_rev, 8)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 7), 0, 0, ++ 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ wlc_phy_resetcca_nphy(pi); ++ ++ if (pi->use_int_tx_iqlo_cal_nphy ++ && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) { ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ mod_radio_reg( ++ pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE0, ++ 1, 1); ++ mod_radio_reg( ++ pi, ++ RADIO_2057_PAD2G_TUNE_PUS_CORE1, ++ 1, 1); ++ } else { ++ mod_radio_reg( ++ pi, ++ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0, ++ 1, 1); ++ mod_radio_reg( ++ pi, ++ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1, ++ 1, 1); ++ } ++ ++ mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4, ++ 0); ++ } else if (NREV_GE(pi->pubpi.phy_rev, 8)) { ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 3), 0, ++ 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ } ++ } ++ } else { ++ mask = ((0x3 << 12) | (0x3 << 14)); ++ mod_phy_reg(pi, 0xa6, mask, pi->tx_rx_cal_phy_saveregs[0]); ++ mod_phy_reg(pi, 0xa7, mask, pi->tx_rx_cal_phy_saveregs[1]); ++ write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[2]); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, ++ &pi->tx_rx_cal_phy_saveregs[3]); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, ++ &pi->tx_rx_cal_phy_saveregs[4]); ++ ++ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[5]); ++ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[6]); ++ } ++} ++ ++void ++wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps) ++{ ++ u16 tssi_reg; ++ s32 temp, pwrindex[2]; ++ s32 idle_tssi[2]; ++ s32 rssi_buf[4]; ++ s32 tssival[2]; ++ u8 tssi_type; ++ ++ tssi_reg = read_phy_reg(pi, 0x1e9); ++ ++ temp = (s32) (tssi_reg & 0x3f); ++ idle_tssi[0] = (temp <= 31) ? temp : (temp - 64); ++ ++ temp = (s32) ((tssi_reg >> 8) & 0x3f); ++ idle_tssi[1] = (temp <= 31) ? temp : (temp - 64); ++ ++ tssi_type = ++ CHSPEC_IS5G(pi->radio_chanspec) ? ++ (u8)NPHY_RSSI_SEL_TSSI_5G : (u8)NPHY_RSSI_SEL_TSSI_2G; ++ ++ wlc_phy_poll_rssi_nphy(pi, tssi_type, rssi_buf, num_samps); ++ ++ tssival[0] = rssi_buf[0] / ((s32) num_samps); ++ tssival[1] = rssi_buf[2] / ((s32) num_samps); ++ ++ pwrindex[0] = idle_tssi[0] - tssival[0] + 64; ++ pwrindex[1] = idle_tssi[1] - tssival[1] + 64; ++ ++ if (pwrindex[0] < 0) ++ pwrindex[0] = 0; ++ else if (pwrindex[0] > 63) ++ pwrindex[0] = 63; ++ ++ if (pwrindex[1] < 0) ++ pwrindex[1] = 0; ++ else if (pwrindex[1] > 63) ++ pwrindex[1] = 63; ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 1, ++ (u32) pwrindex[0], 32, &qdBm_pwrbuf[0]); ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 1, ++ (u32) pwrindex[1], 32, &qdBm_pwrbuf[1]); ++} ++ ++static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core) ++{ ++ int index; ++ u32 bbmult_scale; ++ u16 bbmult; ++ u16 tblentry; ++ ++ struct nphy_txiqcal_ladder ladder_lo[] = { ++ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, ++ {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, ++ {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7} ++ }; ++ ++ struct nphy_txiqcal_ladder ladder_iq[] = { ++ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, ++ {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1}, ++ {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7} ++ }; ++ ++ bbmult = (core == PHY_CORE_0) ? ++ ((pi->nphy_txcal_bbmult >> 8) & 0xff) : ++ (pi->nphy_txcal_bbmult & 0xff); ++ ++ for (index = 0; index < 18; index++) { ++ bbmult_scale = ladder_lo[index].percent * bbmult; ++ bbmult_scale /= 100; ++ ++ tblentry = ++ ((bbmult_scale & 0xff) << 8) | ladder_lo[index].g_env; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index, 16, ++ &tblentry); ++ ++ bbmult_scale = ladder_iq[index].percent * bbmult; ++ bbmult_scale /= 100; ++ ++ tblentry = ++ ((bbmult_scale & 0xff) << 8) | ladder_iq[index].g_env; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index + 32, ++ 16, &tblentry); ++ } ++} ++ ++static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core) ++{ ++ u16 tmp; ++ tmp = read_phy_reg(pi, ((core == PHY_CORE_0) ? 0x1ed : 0x1ee)); ++ ++ tmp = (tmp & (0x7f << 8)) >> 8; ++ return (u8) tmp; ++} ++ ++static void ++wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0, u8 idx1) ++{ ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), idx0); ++ ++ if (NREV_GT(pi->pubpi.phy_rev, 1)) ++ mod_phy_reg(pi, 0x222, (0xff << 0), idx1); ++} ++ ++static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi) ++{ ++ u16 m0m1; ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1); ++ ++ return m0m1; ++} ++ ++static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1) ++{ ++ u16 m0m1 = (u16) ((m0 << 8) | m1); ++ ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m0m1); ++ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &m0m1); ++} ++ ++static void ++wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi, ++ struct nphy_papd_restore_state *state, u8 core) ++{ ++ s32 tone_freq; ++ u8 off_core; ++ u16 mixgain = 0; ++ ++ off_core = core ^ 0x1; ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7) ++ || NREV_GE(pi->pubpi.phy_rev, 8)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 7), ++ wlc_phy_read_lpf_bw_ctl_nphy ++ (pi, ++ 0), 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->pubpi.radiorev == 5) ++ mixgain = (core == 0) ? 0x20 : 0x00; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ mixgain = 0x00; ++ else if ((pi->pubpi.radiorev <= 4) ++ || (pi->pubpi.radiorev == 6)) ++ mixgain = 0x00; ++ } else { ++ if ((pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ mixgain = 0x50; ++ else if ((pi->pubpi.radiorev == 3) ++ || (pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ mixgain = 0x0; ++ } ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), ++ mixgain, (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_tx_pu, ++ 1, (1 << core), 0); ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_tx_pu, ++ 0, (1 << off_core), 0); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), ++ 0, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), ++ 0, (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, ++ (1 << core), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xa6 : 0xa7); ++ state->afeoverride[core] = ++ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5); ++ state->afectrl[off_core] = ++ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa7 : 0xa6); ++ state->afeoverride[off_core] = ++ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa5 : 0x8f); ++ ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7), ++ (0x1 << 2), 0); ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : ++ 0xa5), (0x1 << 2), (0x1 << 2)); ++ ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa7 : 0xa6), ++ (0x1 << 2), (0x1 << 2)); ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa5 : ++ 0x8f), (0x1 << 2), (0x1 << 2)); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ state->pwrup[core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_PWRUP); ++ state->atten[core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_ATTEN); ++ state->pwrup[off_core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_2G_PWRUP); ++ state->atten[off_core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_2G_ATTEN); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_PWRUP, 0xc); ++ ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_ATTEN, 0xf0); ++ else if (pi->pubpi.radiorev == 5) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_ATTEN, ++ (core == 0) ? 0xf7 : 0xf2); ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_ATTEN, 0xf0); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_2G_PWRUP, 0x0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_2G_ATTEN, 0xff); ++ } else { ++ state->pwrup[core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_PWRUP); ++ state->atten[core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_ATTEN); ++ state->pwrup[off_core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_5G_PWRUP); ++ state->atten[off_core] = ++ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_5G_ATTEN); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_PWRUP, 0xc); ++ ++ if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_ATTEN, 0xf4); ++ ++ else ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_ATTEN, 0xf0); ++ ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_5G_PWRUP, 0x0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, ++ TXRXCOUPLE_5G_ATTEN, 0xff); ++ } ++ ++ tone_freq = 4000; ++ ++ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (1) << 13); ++ ++ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_OFF) << 0); ++ ++ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (0) << 13); ++ ++ } else { ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 0); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0, 0); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 0); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 1, 0x3, 0); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0x3, 0); ++ ++ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xa6 : 0xa7); ++ state->afeoverride[core] = ++ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5); ++ ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7), ++ (0x1 << 0) | (0x1 << 1) | (0x1 << 2), 0); ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : ++ 0xa5), ++ (0x1 << 0) | ++ (0x1 << 1) | ++ (0x1 << 2), (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); ++ ++ state->vga_master[core] = ++ READ_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER); ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, 0x2b); ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ state->fbmix[core] = ++ READ_RADIO_REG2(pi, RADIO_2056, RX, core, ++ TXFBMIX_G); ++ state->intpa_master[core] = ++ READ_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_MASTER); ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_G, ++ 0x03); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_MASTER, 0x04); ++ } else { ++ state->fbmix[core] = ++ READ_RADIO_REG2(pi, RADIO_2056, RX, core, ++ TXFBMIX_A); ++ state->intpa_master[core] = ++ READ_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_MASTER); ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_A, ++ 0x03); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_MASTER, 0x04); ++ ++ } ++ ++ tone_freq = 4000; ++ ++ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0); ++ } ++} ++ ++static void ++wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi, ++ struct nphy_papd_restore_state *state) ++{ ++ u8 core; ++ ++ wlc_phy_stopplayback_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_PWRUP, 0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_2G_ATTEN, ++ state->atten[core]); ++ } else { ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_PWRUP, 0); ++ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, ++ TXRXCOUPLE_5G_ATTEN, ++ state->atten[core]); ++ } ++ } ++ ++ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), ++ 1, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ else ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 2), ++ 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), ++ 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, 0x3, 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xa6 : 0xa7, state->afectrl[core]); ++ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : ++ 0xa5, state->afeoverride[core]); ++ } ++ ++ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff, ++ (state->mm & 0xff)); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 7) ++ || NREV_GE(pi->pubpi.phy_rev, 8)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, (0x1 << 7), 0, 0, ++ 1, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 0x3, 1); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 1); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 0, 0x3, 1); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 0, 0x3, 1); ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, ++ state->vga_master[core]); ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, ++ TXFBMIX_G, state->fbmix[core]); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAG_MASTER, ++ state->intpa_master[core]); ++ } else { ++ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, ++ TXFBMIX_A, state->fbmix[core]); ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, ++ INTPAA_MASTER, ++ state->intpa_master[core]); ++ } ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xa6 : 0xa7, state->afectrl[core]); ++ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : ++ 0xa5, state->afeoverride[core]); ++ } ++ ++ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff, ++ (state->mm & 0xff)); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 1); ++ } ++} ++ ++static void ++wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32 start, ++ u32 end) ++{ ++ u32 *buf, *src, *dst, sz; ++ ++ sz = end - start + 1; ++ ++ buf = kmalloc(2 * sizeof(u32) * NPHY_PAPD_EPS_TBL_SIZE, GFP_ATOMIC); ++ if (NULL == buf) ++ return; ++ ++ src = buf; ++ dst = buf + NPHY_PAPD_EPS_TBL_SIZE; ++ ++ wlc_phy_table_read_nphy(pi, ++ (core == ++ PHY_CORE_0 ? NPHY_TBL_ID_EPSILONTBL0 : ++ NPHY_TBL_ID_EPSILONTBL1), ++ NPHY_PAPD_EPS_TBL_SIZE, 0, 32, src); ++ ++ do { ++ u32 phy_a1, phy_a2; ++ s32 phy_a3, phy_a4, phy_a5, phy_a6, phy_a7; ++ ++ phy_a1 = end - min(end, (winsz >> 1)); ++ phy_a2 = min_t(u32, NPHY_PAPD_EPS_TBL_SIZE - 1, ++ end + (winsz >> 1)); ++ phy_a3 = phy_a2 - phy_a1 + 1; ++ phy_a6 = 0; ++ phy_a7 = 0; ++ ++ do { ++ wlc_phy_papd_decode_epsilon(src[phy_a2], &phy_a4, ++ &phy_a5); ++ phy_a6 += phy_a4; ++ phy_a7 += phy_a5; ++ } while (phy_a2-- != phy_a1); ++ ++ phy_a6 /= phy_a3; ++ phy_a7 /= phy_a3; ++ dst[end] = ((u32) phy_a7 << 13) | ((u32) phy_a6 & 0x1fff); ++ } while (end-- != start); ++ ++ wlc_phy_table_write_nphy(pi, ++ (core == ++ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 : ++ NPHY_TBL_ID_EPSILONTBL1, sz, start, 32, dst); ++ ++ kfree(buf); ++} ++ ++static void ++wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains, ++ enum phy_cal_mode cal_mode, u8 core) ++{ ++ u16 phy_a1, phy_a2, phy_a3; ++ u16 phy_a4, phy_a5; ++ bool phy_a6; ++ u8 phy_a7, m[2]; ++ u32 phy_a8 = 0; ++ struct nphy_txgains phy_a9; ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ return; ++ ++ phy_a7 = (core == PHY_CORE_0) ? 1 : 0; ++ ++ phy_a6 = ((cal_mode == CAL_GCTRL) ++ || (cal_mode == CAL_SOFT)) ? true : false; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ phy_a9 = wlc_phy_get_tx_gain_nphy(pi); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ phy_a5 = ((phy_a9.txlpf[core] << 15) | ++ (phy_a9.txgm[core] << 12) | ++ (phy_a9.pga[core] << 8) | ++ (txgains->gains.pad[core] << 3) | ++ (phy_a9.ipa[core])); ++ else ++ phy_a5 = ((phy_a9.txlpf[core] << 15) | ++ (phy_a9.txgm[core] << 12) | ++ (txgains->gains.pga[core] << 8) | ++ (phy_a9.pad[core] << 3) | (phy_a9.ipa[core])); ++ ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_txgain, ++ phy_a5, (1 << core), 0); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((pi->pubpi.radiorev <= 4) ++ || (pi->pubpi.radiorev == 6)) ++ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? ++ 60 : 79; ++ else ++ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? ++ 45 : 64; ++ } else { ++ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107; ++ } ++ ++ m[phy_a7] = 0; ++ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]); ++ ++ phy_a2 = 63; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((pi->pubpi.radiorev == 4) ++ || (pi->pubpi.radiorev == 6)) { ++ phy_a1 = 30; ++ phy_a3 = 30; ++ } else { ++ phy_a1 = 25; ++ phy_a3 = 25; ++ } ++ } else { ++ if ((pi->pubpi.radiorev == 5) ++ || (pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ phy_a1 = 25; ++ phy_a3 = 25; ++ } else { ++ phy_a1 = 35; ++ phy_a3 = 35; ++ } ++ } ++ ++ if (cal_mode == CAL_GCTRL) { ++ if ((pi->pubpi.radiorev == 5) ++ && (CHSPEC_IS2G(pi->radio_chanspec))) ++ phy_a1 = 55; ++ else if (((pi->pubpi.radiorev == 7) && ++ (CHSPEC_IS2G(pi->radio_chanspec))) || ++ ((pi->pubpi.radiorev == 8) && ++ (CHSPEC_IS2G(pi->radio_chanspec)))) ++ phy_a1 = 60; ++ else ++ phy_a1 = 63; ++ ++ } else if ((cal_mode != CAL_FULL) && (cal_mode != CAL_SOFT)) { ++ ++ phy_a1 = 35; ++ phy_a3 = 35; ++ } ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (1) << 13); ++ ++ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (0) << 13); ++ ++ write_phy_reg(pi, 0x2a1, 0x80); ++ write_phy_reg(pi, 0x2a2, 0x100); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 4), (11) << 4); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 8), (11) << 8); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 0), (0x3) << 0); ++ ++ write_phy_reg(pi, 0x2e5, 0x20); ++ ++ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0); ++ ++ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0); ++ ++ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), ++ 1, ((core == 0) ? 1 : 2), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), ++ 0, ((core == 0) ? 2 : 1), 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ ++ write_phy_reg(pi, 0x2be, 1); ++ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), ++ 0, 0x3, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ ++ wlc_phy_table_write_nphy(pi, ++ (core == ++ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 ++ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3, ++ 32, &phy_a8); ++ ++ if (cal_mode != CAL_GCTRL) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) ++ wlc_phy_a1_nphy(pi, core, 5, 0, 35); ++ } ++ ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_txgain, ++ phy_a5, (1 << core), 1); ++ ++ } else { ++ ++ if (txgains) { ++ if (txgains->useindex) { ++ phy_a4 = 15 - ((txgains->index) >> 3); ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) ++ phy_a5 = 0x00f7 | (phy_a4 << 8); ++ ++ else ++ if (NREV_IS(pi->pubpi.phy_rev, 5)) ++ phy_a5 = 0x10f7 | (phy_a4 << 8); ++ else ++ phy_a5 = 0x50f7 | (phy_a4 << 8); ++ } else { ++ phy_a5 = 0x70f7 | (phy_a4 << 8); ++ } ++ wlc_phy_rfctrl_override_nphy(pi, ++ (0x1 << 13), ++ phy_a5, ++ (1 << core), 0); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, ++ (0x1 << 13), ++ 0x5bf7, ++ (1 << core), 0); ++ } ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 45 : 64; ++ else ++ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107; ++ ++ m[phy_a7] = 0; ++ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]); ++ ++ phy_a2 = 63; ++ ++ if (cal_mode == CAL_FULL) { ++ phy_a1 = 25; ++ phy_a3 = 25; ++ } else if (cal_mode == CAL_SOFT) { ++ phy_a1 = 25; ++ phy_a3 = 25; ++ } else if (cal_mode == CAL_GCTRL) { ++ phy_a1 = 63; ++ phy_a3 = 25; ++ } else { ++ ++ phy_a1 = 25; ++ phy_a3 = 25; ++ } ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (1) << 0); ++ ++ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (1) << 13); ++ ++ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (0) << 13); ++ ++ write_phy_reg(pi, 0x2a1, 0x20); ++ write_phy_reg(pi, 0x2a2, 0x60); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0xf << 4), (9) << 4); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0xf << 8), (9) << 8); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0xf << 0), (0x2) << 0); ++ ++ write_phy_reg(pi, 0x2e5, 0x20); ++ } else { ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 11), (1) << 11); ++ ++ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 11), (0) << 11); ++ ++ write_phy_reg(pi, 0x2a1, 0x80); ++ write_phy_reg(pi, 0x2a2, 0x600); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 4), (0) << 4); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 8), (0) << 8); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x7 << 0), (0x3) << 0); ++ ++ mod_phy_reg(pi, 0x2a0, (0x3f << 8), (0x20) << 8); ++ ++ } ++ ++ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0); ++ ++ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0); ++ ++ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0x3, 0); ++ ++ write_phy_reg(pi, 0x2be, 1); ++ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000); ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0); ++ ++ wlc_phy_table_write_nphy(pi, ++ (core == ++ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 ++ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3, ++ 32, &phy_a8); ++ ++ if (cal_mode != CAL_GCTRL) ++ wlc_phy_a1_nphy(pi, core, 5, 0, 40); ++ } ++} ++ ++static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core) ++{ ++ int phy_a1; ++ int phy_a2; ++ bool phy_a3; ++ struct nphy_ipa_txcalgains phy_a4; ++ bool phy_a5 = false; ++ bool phy_a6 = true; ++ s32 phy_a7, phy_a8; ++ u32 phy_a9; ++ int phy_a10; ++ bool phy_a11 = false; ++ int phy_a12; ++ u8 phy_a13 = 0; ++ u8 phy_a14; ++ u8 *phy_a15 = NULL; ++ ++ phy_a4.useindex = true; ++ phy_a12 = start_gain; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ phy_a2 = 20; ++ phy_a1 = 1; ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->pubpi.radiorev == 5) { ++ ++ phy_a15 = pad_gain_codes_used_2057rev5; ++ phy_a13 = ++ sizeof(pad_gain_codes_used_2057rev5) / ++ sizeof(pad_gain_codes_used_2057rev5 ++ [0]) - 1; ++ ++ } else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ ++ phy_a15 = pad_gain_codes_used_2057rev7; ++ phy_a13 = ++ sizeof(pad_gain_codes_used_2057rev7) / ++ sizeof(pad_gain_codes_used_2057rev7 ++ [0]) - 1; ++ ++ } else { ++ ++ phy_a15 = pad_all_gain_codes_2057; ++ phy_a13 = sizeof(pad_all_gain_codes_2057) / ++ sizeof(pad_all_gain_codes_2057[0]) - ++ 1; ++ } ++ ++ } else { ++ ++ phy_a15 = pga_all_gain_codes_2057; ++ phy_a13 = sizeof(pga_all_gain_codes_2057) / ++ sizeof(pga_all_gain_codes_2057[0]) - 1; ++ } ++ ++ phy_a14 = 0; ++ ++ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ phy_a4.gains.pad[core] = ++ (u16) phy_a15[phy_a12]; ++ else ++ phy_a4.gains.pga[core] = ++ (u16) phy_a15[phy_a12]; ++ ++ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core); ++ ++ wlc_phy_table_read_nphy(pi, ++ (core == ++ PHY_CORE_0 ? ++ NPHY_TBL_ID_EPSILONTBL0 : ++ NPHY_TBL_ID_EPSILONTBL1), 1, ++ 63, 32, &phy_a9); ++ ++ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8); ++ ++ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) || ++ (phy_a8 == 4095) || (phy_a8 == -4096)); ++ ++ if (!phy_a6 && (phy_a3 != phy_a5)) { ++ if (!phy_a3) ++ phy_a12 -= (u8) phy_a1; ++ ++ phy_a11 = true; ++ break; ++ } ++ ++ if (phy_a3) ++ phy_a12 += (u8) phy_a1; ++ else ++ phy_a12 -= (u8) phy_a1; ++ ++ if ((phy_a12 < phy_a14) || (phy_a12 > phy_a13)) { ++ if (phy_a12 < phy_a14) ++ phy_a12 = phy_a14; ++ else ++ phy_a12 = phy_a13; ++ ++ phy_a11 = true; ++ break; ++ } ++ ++ phy_a6 = false; ++ phy_a5 = phy_a3; ++ } ++ ++ } else { ++ phy_a2 = 10; ++ phy_a1 = 8; ++ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) { ++ phy_a4.index = (u8) phy_a12; ++ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core); ++ ++ wlc_phy_table_read_nphy(pi, ++ (core == ++ PHY_CORE_0 ? ++ NPHY_TBL_ID_EPSILONTBL0 : ++ NPHY_TBL_ID_EPSILONTBL1), 1, ++ 63, 32, &phy_a9); ++ ++ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8); ++ ++ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) || ++ (phy_a8 == 4095) || (phy_a8 == -4096)); ++ ++ if (!phy_a6 && (phy_a3 != phy_a5)) { ++ if (!phy_a3) ++ phy_a12 -= (u8) phy_a1; ++ ++ phy_a11 = true; ++ break; ++ } ++ ++ if (phy_a3) ++ phy_a12 += (u8) phy_a1; ++ else ++ phy_a12 -= (u8) phy_a1; ++ ++ if ((phy_a12 < 0) || (phy_a12 > 127)) { ++ if (phy_a12 < 0) ++ phy_a12 = 0; ++ else ++ phy_a12 = 127; ++ ++ phy_a11 = true; ++ break; ++ } ++ ++ phy_a6 = false; ++ phy_a5 = phy_a3; ++ } ++ ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ return (u8) phy_a15[phy_a12]; ++ else ++ return (u8) phy_a12; ++ ++} ++ ++static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal) ++{ ++ struct nphy_ipa_txcalgains phy_b1[2]; ++ struct nphy_papd_restore_state phy_b2; ++ bool phy_b3; ++ u8 phy_b4; ++ u8 phy_b5; ++ s16 phy_b6, phy_b7, phy_b8; ++ u16 phy_b9; ++ s16 phy_b10, phy_b11, phy_b12; ++ ++ phy_b11 = 0; ++ phy_b12 = 0; ++ phy_b7 = 0; ++ phy_b8 = 0; ++ phy_b6 = 0; ++ ++ if (pi->nphy_papd_skip == 1) ++ return; ++ ++ phy_b3 = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); ++ if (!phy_b3) ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ pi->nphy_force_papd_cal = false; ++ ++ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) ++ pi->nphy_papd_tx_gain_at_last_cal[phy_b5] = ++ wlc_phy_txpwr_idx_cur_get_nphy(pi, phy_b5); ++ ++ pi->nphy_papd_last_cal = pi->sh->now; ++ pi->nphy_papd_recal_counter++; ++ ++ phy_b4 = pi->nphy_txpwrctrl; ++ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL0, 64, 0, 32, ++ nphy_papd_scaltbl); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL1, 64, 0, 32, ++ nphy_papd_scaltbl); ++ ++ phy_b9 = read_phy_reg(pi, 0x01); ++ mod_phy_reg(pi, 0x01, (0x1 << 15), 0); ++ ++ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { ++ s32 i, val = 0; ++ for (i = 0; i < 64; i++) ++ wlc_phy_table_write_nphy(pi, ++ ((phy_b5 == ++ PHY_CORE_0) ? ++ NPHY_TBL_ID_EPSILONTBL0 : ++ NPHY_TBL_ID_EPSILONTBL1), 1, ++ i, 32, &val); ++ } ++ ++ wlc_phy_ipa_restore_tx_digi_filts_nphy(pi); ++ ++ phy_b2.mm = wlc_phy_ipa_get_bbmult_nphy(pi); ++ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { ++ wlc_phy_papd_cal_setup_nphy(pi, &phy_b2, phy_b5); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if ((pi->pubpi.radiorev == 3) ++ || (pi->pubpi.radiorev == 4) ++ || (pi->pubpi.radiorev == 6)) { ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ 23; ++ } else if (pi->pubpi.radiorev == 5) { ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ 0; ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ wlc_phy_a3_nphy( ++ pi, ++ pi-> ++ nphy_papd_cal_gain_index ++ [phy_b5], ++ phy_b5); ++ ++ } else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) { ++ ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ 0; ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ wlc_phy_a3_nphy( ++ pi, ++ pi-> ++ nphy_papd_cal_gain_index ++ [phy_b5], ++ phy_b5); ++ ++ } ++ ++ phy_b1[phy_b5].gains.pad[phy_b5] = ++ pi->nphy_papd_cal_gain_index[phy_b5]; ++ ++ } else { ++ pi->nphy_papd_cal_gain_index[phy_b5] = 0; ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ wlc_phy_a3_nphy( ++ pi, ++ pi-> ++ nphy_papd_cal_gain_index ++ [phy_b5], phy_b5); ++ phy_b1[phy_b5].gains.pga[phy_b5] = ++ pi->nphy_papd_cal_gain_index[phy_b5]; ++ } ++ } else { ++ phy_b1[phy_b5].useindex = true; ++ phy_b1[phy_b5].index = 16; ++ phy_b1[phy_b5].index = ++ wlc_phy_a3_nphy(pi, phy_b1[phy_b5].index, ++ phy_b5); ++ ++ pi->nphy_papd_cal_gain_index[phy_b5] = ++ 15 - ((phy_b1[phy_b5].index) >> 3); ++ } ++ ++ switch (pi->nphy_papd_cal_type) { ++ case 0: ++ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_FULL, phy_b5); ++ break; ++ case 1: ++ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_SOFT, phy_b5); ++ break; ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2); ++ } ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) ++ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2); ++ ++ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { ++ int eps_offset = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ if (pi->pubpi.radiorev == 3) ++ eps_offset = -2; ++ else if (pi->pubpi.radiorev == 5) ++ eps_offset = 3; ++ else ++ eps_offset = -1; ++ } else { ++ eps_offset = 2; ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ phy_b8 = phy_b1[phy_b5].gains.pad[phy_b5]; ++ phy_b10 = 0; ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) { ++ phy_b12 = -( ++ nphy_papd_padgain_dlt_2g_2057rev3n4 ++ [phy_b8] + 1) / 2; ++ phy_b10 = -1; ++ } else if (pi->pubpi.radiorev == 5) { ++ phy_b12 = -( ++ nphy_papd_padgain_dlt_2g_2057rev5 ++ [phy_b8] + 1) / 2; ++ } else if ((pi->pubpi.radiorev == 7) || ++ (pi->pubpi.radiorev == 8)) { ++ phy_b12 = -( ++ nphy_papd_padgain_dlt_2g_2057rev7 ++ [phy_b8] + 1) / 2; ++ } ++ } else { ++ phy_b7 = phy_b1[phy_b5].gains.pga[phy_b5]; ++ if ((pi->pubpi.radiorev == 3) || ++ (pi->pubpi.radiorev == 4) || ++ (pi->pubpi.radiorev == 6)) ++ phy_b11 = ++ -(nphy_papd_pgagain_dlt_5g_2057 ++ [phy_b7] ++ + 1) / 2; ++ else if ((pi->pubpi.radiorev == 7) ++ || (pi->pubpi.radiorev == 8)) ++ phy_b11 = -( ++ nphy_papd_pgagain_dlt_5g_2057rev7 ++ [phy_b7] + 1) / 2; ++ ++ phy_b10 = -9; ++ } ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) ++ phy_b6 = ++ -60 + 27 + eps_offset + phy_b12 + ++ phy_b10; ++ else ++ phy_b6 = ++ -60 + 27 + eps_offset + phy_b11 + ++ phy_b10; ++ ++ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 : ++ 0x29c, (0x1ff << 7), (phy_b6) << 7); ++ ++ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6; ++ } else { ++ if (NREV_LT(pi->pubpi.phy_rev, 5)) ++ eps_offset = 4; ++ else ++ eps_offset = 2; ++ ++ phy_b7 = 15 - ((phy_b1[phy_b5].index) >> 3); ++ ++ if (CHSPEC_IS2G(pi->radio_chanspec)) { ++ phy_b11 = ++ -(nphy_papd_pga_gain_delta_ipa_2g[ ++ phy_b7] + ++ 1) / 2; ++ phy_b10 = 0; ++ } else { ++ phy_b11 = ++ -(nphy_papd_pga_gain_delta_ipa_5g[ ++ phy_b7] + ++ 1) / 2; ++ phy_b10 = -9; ++ } ++ ++ phy_b6 = -60 + 27 + eps_offset + phy_b11 + phy_b10; ++ ++ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 : ++ 0x29c, (0x1ff << 7), (phy_b6) << 7); ++ ++ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6; ++ } ++ } ++ ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6)) { ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (0) << 13); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 13), (0) << 13); ++ ++ } else { ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 11), (0) << 11); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 : ++ 0x2a4, (0x1 << 11), (0) << 11); ++ ++ } ++ pi->nphy_papdcomp = NPHY_PAPD_COMP_ON; ++ ++ write_phy_reg(pi, 0x01, phy_b9); ++ ++ wlc_phy_ipa_set_tx_digi_filts_nphy(pi); ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, phy_b4); ++ if (phy_b4 == PHY_TPC_HW_OFF) { ++ wlc_phy_txpwr_index_nphy(pi, (1 << 0), ++ (s8) (pi->nphy_txpwrindex[0]. ++ index_internal), false); ++ wlc_phy_txpwr_index_nphy(pi, (1 << 1), ++ (s8) (pi->nphy_txpwrindex[1]. ++ index_internal), false); ++ } ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ if (!phy_b3) ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype) ++{ ++ struct nphy_txgains target_gain; ++ u8 tx_pwr_ctrl_state; ++ bool fullcal = true; ++ bool restore_tx_gain = false; ++ bool mphase; ++ ++ if (PHY_MUTED(pi)) ++ return; ++ ++ if (caltype == PHY_PERICAL_AUTO) ++ fullcal = (pi->radio_chanspec != pi->nphy_txiqlocal_chanspec); ++ else if (caltype == PHY_PERICAL_PARTIAL) ++ fullcal = false; ++ ++ if (pi->cal_type_override != PHY_PERICAL_AUTO) ++ fullcal = ++ (pi->cal_type_override == ++ PHY_PERICAL_FULL) ? true : false; ++ ++ if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) { ++ if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec) ++ wlc_phy_cal_perical_mphase_restart(pi); ++ } ++ ++ if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL)) ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); ++ ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ wlc_phyreg_enter((struct brcms_phy_pub *) pi); ++ ++ if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_IDLE) || ++ (pi->mphase_cal_phase_id == MPHASE_CAL_STATE_INIT)) { ++ pi->nphy_cal_orig_pwr_idx[0] = ++ (u8) ((read_phy_reg(pi, 0x1ed) >> 8) & 0x7f); ++ pi->nphy_cal_orig_pwr_idx[1] = ++ (u8) ((read_phy_reg(pi, 0x1ee) >> 8) & 0x7f); ++ ++ if (pi->nphy_txpwrctrl != PHY_TPC_HW_OFF) { ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, ++ 0x110, 16, ++ pi->nphy_cal_orig_tx_gain); ++ } else { ++ pi->nphy_cal_orig_tx_gain[0] = 0; ++ pi->nphy_cal_orig_tx_gain[1] = 0; ++ } ++ } ++ target_gain = wlc_phy_get_tx_gain_nphy(pi); ++ tx_pwr_ctrl_state = pi->nphy_txpwrctrl; ++ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); ++ ++ if (pi->antsel_type == ANTSEL_2x3) ++ wlc_phy_antsel_init((struct brcms_phy_pub *) pi, true); ++ ++ mphase = (pi->mphase_cal_phase_id != MPHASE_CAL_STATE_IDLE); ++ if (!mphase) { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ wlc_phy_precal_txgain_nphy(pi); ++ pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi); ++ restore_tx_gain = true; ++ ++ target_gain = pi->nphy_cal_target_gain; ++ } ++ if (0 == ++ wlc_phy_cal_txiqlo_nphy(pi, target_gain, fullcal, ++ mphase)) { ++ if (PHY_IPA(pi)) ++ wlc_phy_a4(pi, true); ++ ++ wlc_phyreg_exit((struct brcms_phy_pub *) pi); ++ wlapi_enable_mac(pi->sh->physhim); ++ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, ++ 10000); ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ wlc_phyreg_enter((struct brcms_phy_pub *) pi); ++ ++ if (0 == wlc_phy_cal_rxiq_nphy(pi, target_gain, ++ (pi->first_cal_after_assoc || ++ (pi->cal_type_override == ++ PHY_PERICAL_FULL)) ? 2 : 0, false)) { ++ wlc_phy_savecal_nphy(pi); ++ ++ wlc_phy_txpwrctrl_coeff_setup_nphy(pi); ++ ++ pi->nphy_perical_last = pi->sh->now; ++ } ++ } ++ if (caltype != PHY_PERICAL_AUTO) ++ wlc_phy_rssi_cal_nphy(pi); ++ ++ if (pi->first_cal_after_assoc ++ || (pi->cal_type_override == PHY_PERICAL_FULL)) { ++ pi->first_cal_after_assoc = false; ++ wlc_phy_txpwrctrl_idle_tssi_nphy(pi); ++ wlc_phy_txpwrctrl_pwr_setup_nphy(pi); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_radio205x_vcocal_nphy(pi); ++ } else { ++ switch (pi->mphase_cal_phase_id) { ++ case MPHASE_CAL_STATE_INIT: ++ pi->nphy_perical_last = pi->sh->now; ++ pi->nphy_txiqlocal_chanspec = pi->radio_chanspec; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_precal_txgain_nphy(pi); ++ ++ pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi); ++ pi->mphase_cal_phase_id++; ++ break; ++ ++ case MPHASE_CAL_STATE_TXPHASE0: ++ case MPHASE_CAL_STATE_TXPHASE1: ++ case MPHASE_CAL_STATE_TXPHASE2: ++ case MPHASE_CAL_STATE_TXPHASE3: ++ case MPHASE_CAL_STATE_TXPHASE4: ++ case MPHASE_CAL_STATE_TXPHASE5: ++ if ((pi->radar_percal_mask & 0x10) != 0) ++ pi->nphy_rxcal_active = true; ++ ++ if (wlc_phy_cal_txiqlo_nphy ++ (pi, pi->nphy_cal_target_gain, fullcal, ++ true) != 0) { ++ ++ wlc_phy_cal_perical_mphase_reset(pi); ++ break; ++ } ++ ++ if (NREV_LE(pi->pubpi.phy_rev, 2) && ++ (pi->mphase_cal_phase_id == ++ MPHASE_CAL_STATE_TXPHASE4)) ++ pi->mphase_cal_phase_id += 2; ++ else ++ pi->mphase_cal_phase_id++; ++ break; ++ ++ case MPHASE_CAL_STATE_PAPDCAL: ++ if ((pi->radar_percal_mask & 0x2) != 0) ++ pi->nphy_rxcal_active = true; ++ ++ if (PHY_IPA(pi)) ++ wlc_phy_a4(pi, true); ++ ++ pi->mphase_cal_phase_id++; ++ break; ++ ++ case MPHASE_CAL_STATE_RXCAL: ++ if ((pi->radar_percal_mask & 0x1) != 0) ++ pi->nphy_rxcal_active = true; ++ if (wlc_phy_cal_rxiq_nphy(pi, target_gain, ++ (pi->first_cal_after_assoc || ++ (pi->cal_type_override == ++ PHY_PERICAL_FULL)) ? 2 : 0, ++ false) == 0) ++ wlc_phy_savecal_nphy(pi); ++ ++ pi->mphase_cal_phase_id++; ++ break; ++ ++ case MPHASE_CAL_STATE_RSSICAL: ++ if ((pi->radar_percal_mask & 0x4) != 0) ++ pi->nphy_rxcal_active = true; ++ wlc_phy_txpwrctrl_coeff_setup_nphy(pi); ++ wlc_phy_rssi_cal_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_radio205x_vcocal_nphy(pi); ++ ++ restore_tx_gain = true; ++ ++ if (pi->first_cal_after_assoc) ++ pi->mphase_cal_phase_id++; ++ else ++ wlc_phy_cal_perical_mphase_reset(pi); ++ ++ break; ++ ++ case MPHASE_CAL_STATE_IDLETSSI: ++ if ((pi->radar_percal_mask & 0x8) != 0) ++ pi->nphy_rxcal_active = true; ++ ++ if (pi->first_cal_after_assoc) { ++ pi->first_cal_after_assoc = false; ++ wlc_phy_txpwrctrl_idle_tssi_nphy(pi); ++ wlc_phy_txpwrctrl_pwr_setup_nphy(pi); ++ } ++ ++ wlc_phy_cal_perical_mphase_reset(pi); ++ break; ++ ++ default: ++ wlc_phy_cal_perical_mphase_reset(pi); ++ break; ++ } ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if (restore_tx_gain) { ++ if (tx_pwr_ctrl_state != PHY_TPC_HW_OFF) { ++ ++ wlc_phy_txpwr_index_nphy(pi, 1, ++ pi-> ++ nphy_cal_orig_pwr_idx ++ [0], false); ++ wlc_phy_txpwr_index_nphy(pi, 2, ++ pi-> ++ nphy_cal_orig_pwr_idx ++ [1], false); ++ ++ pi->nphy_txpwrindex[0].index = -1; ++ pi->nphy_txpwrindex[1].index = -1; ++ } else { ++ wlc_phy_txpwr_index_nphy(pi, (1 << 0), ++ (s8) (pi-> ++ nphy_txpwrindex ++ [0]. ++ index_internal), ++ false); ++ wlc_phy_txpwr_index_nphy(pi, (1 << 1), ++ (s8) (pi-> ++ nphy_txpwrindex ++ [1]. ++ index_internal), ++ false); ++ } ++ } ++ } ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); ++ wlc_phyreg_exit((struct brcms_phy_pub *) pi); ++ wlapi_enable_mac(pi->sh->physhim); ++} ++ ++int ++wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, ++ bool fullcal, bool mphase) ++{ ++ u16 val; ++ u16 tbl_buf[11]; ++ u8 cal_cnt; ++ u16 cal_cmd; ++ u8 num_cals, max_cal_cmds; ++ u16 core_no, cal_type; ++ u16 diq_start = 0; ++ u8 phy_bw; ++ u16 max_val; ++ u16 tone_freq; ++ u16 gain_save[2]; ++ u16 cal_gain[2]; ++ struct nphy_iqcal_params cal_params[2]; ++ u32 tbl_len; ++ void *tbl_ptr; ++ bool ladder_updated[2]; ++ u8 mphase_cal_lastphase = 0; ++ int bcmerror = 0; ++ bool phyhang_avoid_state = false; ++ ++ u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { ++ 0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901, ++ 0x1902, ++ 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607, ++ 0x6407 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { ++ 0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400, ++ 0x3200, ++ 0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406, ++ 0x6407 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { ++ 0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201, ++ 0x1202, ++ 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207, ++ 0x4707 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { ++ 0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900, ++ 0x2300, ++ 0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706, ++ 0x4707 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_startcoefs[] = { ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { ++ 0x8123, 0x8264, 0x8086, 0x8245, 0x8056, ++ 0x9123, 0x9264, 0x9086, 0x9245, 0x9056 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_cmds_recal[] = { ++ 0x8101, 0x8253, 0x8053, 0x8234, 0x8034, ++ 0x9101, 0x9253, 0x9053, 0x9234, 0x9034 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { ++ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234, ++ 0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234 ++ }; ++ ++ u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { ++ 0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223, ++ 0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223 ++ }; ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 4)) { ++ phyhang_avoid_state = pi->phyhang_avoid; ++ pi->phyhang_avoid = false; ++ } ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ phy_bw = 40; ++ else ++ phy_bw = 20; ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); ++ ++ for (core_no = 0; core_no <= 1; core_no++) { ++ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, ++ &cal_params[core_no]); ++ cal_gain[core_no] = cal_params[core_no].cal_gain; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); ++ ++ wlc_phy_txcal_radio_setup_nphy(pi); ++ ++ wlc_phy_txcal_physetup_nphy(pi); ++ ++ ladder_updated[0] = ladder_updated[1] = false; ++ if (!(NREV_GE(pi->pubpi.phy_rev, 6) || ++ (NREV_IS(pi->pubpi.phy_rev, 5) && PHY_IPA(pi) ++ && (CHSPEC_IS2G(pi->radio_chanspec))))) { ++ ++ if (phy_bw == 40) { ++ tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_40; ++ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_40); ++ } else { ++ tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_20; ++ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_20); ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 0, ++ 16, tbl_ptr); ++ ++ if (phy_bw == 40) { ++ tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_40; ++ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_40); ++ } else { ++ tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_20; ++ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_20); ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 32, ++ 16, tbl_ptr); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ write_phy_reg(pi, 0xc2, 0x8ad9); ++ else ++ write_phy_reg(pi, 0xc2, 0x8aa9); ++ ++ max_val = 250; ++ tone_freq = (phy_bw == 20) ? 2500 : 5000; ++ ++ if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) { ++ wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff, 0, 1, 0, false); ++ bcmerror = 0; ++ } else { ++ bcmerror = ++ wlc_phy_tx_tone_nphy(pi, tone_freq, max_val, 1, 0, ++ false); ++ } ++ ++ if (bcmerror == 0) { ++ ++ if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) { ++ tbl_ptr = pi->mphase_txcal_bestcoeffs; ++ tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs); ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ tbl_len -= 2; ++ } else { ++ if ((!fullcal) && (pi->nphy_txiqlocal_coeffsvalid)) { ++ ++ tbl_ptr = pi->nphy_txiqlocal_bestc; ++ tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc); ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ tbl_len -= 2; ++ } else { ++ ++ fullcal = true; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ tbl_ptr = ++ tbl_tx_iqlo_cal_startcoefs_nphyrev3; ++ tbl_len = ARRAY_SIZE( ++ tbl_tx_iqlo_cal_startcoefs_nphyrev3); ++ } else { ++ tbl_ptr = tbl_tx_iqlo_cal_startcoefs; ++ tbl_len = ARRAY_SIZE( ++ tbl_tx_iqlo_cal_startcoefs); ++ } ++ } ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 64, ++ 16, tbl_ptr); ++ ++ if (fullcal) { ++ max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ? ++ ARRAY_SIZE( ++ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3) : ++ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal); ++ } else { ++ max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ? ++ ARRAY_SIZE( ++ tbl_tx_iqlo_cal_cmds_recal_nphyrev3) : ++ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal); ++ } ++ ++ if (mphase) { ++ cal_cnt = pi->mphase_txcal_cmdidx; ++ if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds) ++ num_cals = cal_cnt + pi->mphase_txcal_numcmds; ++ else ++ num_cals = max_cal_cmds; ++ } else { ++ cal_cnt = 0; ++ num_cals = max_cal_cmds; ++ } ++ ++ for (; cal_cnt < num_cals; cal_cnt++) { ++ ++ if (fullcal) { ++ cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ? ++ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3 ++ [cal_cnt] : ++ tbl_tx_iqlo_cal_cmds_fullcal[cal_cnt]; ++ } else { ++ cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ? ++ tbl_tx_iqlo_cal_cmds_recal_nphyrev3[ ++ cal_cnt] ++ : tbl_tx_iqlo_cal_cmds_recal[cal_cnt]; ++ } ++ ++ core_no = ((cal_cmd & 0x3000) >> 12); ++ cal_type = ((cal_cmd & 0x0F00) >> 8); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 6) || ++ (NREV_IS(pi->pubpi.phy_rev, 5) && ++ PHY_IPA(pi) ++ && (CHSPEC_IS2G(pi->radio_chanspec)))) { ++ if (!ladder_updated[core_no]) { ++ wlc_phy_update_txcal_ladder_nphy( ++ pi, ++ core_no); ++ ladder_updated[core_no] = true; ++ } ++ } ++ ++ val = ++ (cal_params[core_no]. ++ ncorr[cal_type] << 8) | NPHY_N_GCTL; ++ write_phy_reg(pi, 0xc1, val); ++ ++ if ((cal_type == 1) || (cal_type == 3) ++ || (cal_type == 4)) { ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ 1, 69 + core_no, 16, ++ tbl_buf); ++ ++ diq_start = tbl_buf[0]; ++ ++ tbl_buf[0] = 0; ++ wlc_phy_table_write_nphy(pi, ++ NPHY_TBL_ID_IQLOCAL, 1, ++ 69 + core_no, 16, ++ tbl_buf); ++ } ++ ++ write_phy_reg(pi, 0xc0, cal_cmd); ++ ++ SPINWAIT(((read_phy_reg(pi, 0xc0) & 0xc000) != 0), ++ 20000); ++ if (WARN(read_phy_reg(pi, 0xc0) & 0xc000, ++ "HW error: txiq calib")) ++ return -EIO; ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ tbl_len, 96, 16, tbl_buf); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ tbl_len, 64, 16, tbl_buf); ++ ++ if ((cal_type == 1) || (cal_type == 3) ++ || (cal_type == 4)) { ++ ++ tbl_buf[0] = diq_start; ++ ++ } ++ ++ } ++ ++ if (mphase) { ++ pi->mphase_txcal_cmdidx = num_cals; ++ if (pi->mphase_txcal_cmdidx >= max_cal_cmds) ++ pi->mphase_txcal_cmdidx = 0; ++ } ++ ++ mphase_cal_lastphase = ++ (NREV_LE(pi->pubpi.phy_rev, 2)) ? ++ MPHASE_CAL_STATE_TXPHASE4 : MPHASE_CAL_STATE_TXPHASE5; ++ ++ if (!mphase ++ || (pi->mphase_cal_phase_id == mphase_cal_lastphase)) { ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 96, ++ 16, tbl_buf); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, ++ 16, tbl_buf); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ ++ tbl_buf[0] = 0; ++ tbl_buf[1] = 0; ++ tbl_buf[2] = 0; ++ tbl_buf[3] = 0; ++ ++ } ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, ++ 16, tbl_buf); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 101, ++ 16, tbl_buf); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, ++ 16, tbl_buf); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, ++ 16, tbl_buf); ++ ++ tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc); ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ tbl_len -= 2; ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ tbl_len, 96, 16, ++ pi->nphy_txiqlocal_bestc); ++ ++ pi->nphy_txiqlocal_coeffsvalid = true; ++ pi->nphy_txiqlocal_chanspec = pi->radio_chanspec; ++ } else { ++ tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs); ++ if (NREV_LT(pi->pubpi.phy_rev, 3)) ++ tbl_len -= 2; ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ tbl_len, 96, 16, ++ pi->mphase_txcal_bestcoeffs); ++ } ++ ++ wlc_phy_stopplayback_nphy(pi); ++ ++ write_phy_reg(pi, 0xc2, 0x0000); ++ ++ } ++ ++ wlc_phy_txcal_phycleanup_nphy(pi); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ gain_save); ++ ++ wlc_phy_txcal_radio_cleanup_nphy(pi); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) { ++ if (!mphase ++ || (pi->mphase_cal_phase_id == mphase_cal_lastphase)) ++ wlc_phy_tx_iq_war_nphy(pi); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 4)) ++ pi->phyhang_avoid = phyhang_avoid_state; ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ return bcmerror; ++} ++ ++static void wlc_phy_reapply_txcal_coeffs_nphy(struct brcms_phy *pi) ++{ ++ u16 tbl_buf[7]; ++ ++ if ((pi->nphy_txiqlocal_chanspec == pi->radio_chanspec) && ++ (pi->nphy_txiqlocal_coeffsvalid)) { ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, ++ ARRAY_SIZE(tbl_buf), 80, 16, tbl_buf); ++ ++ if ((pi->nphy_txiqlocal_bestc[0] != tbl_buf[0]) || ++ (pi->nphy_txiqlocal_bestc[1] != tbl_buf[1]) || ++ (pi->nphy_txiqlocal_bestc[2] != tbl_buf[2]) || ++ (pi->nphy_txiqlocal_bestc[3] != tbl_buf[3])) { ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, ++ 16, pi->nphy_txiqlocal_bestc); ++ ++ tbl_buf[0] = 0; ++ tbl_buf[1] = 0; ++ tbl_buf[2] = 0; ++ tbl_buf[3] = 0; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, ++ 16, tbl_buf); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, ++ 16, ++ &pi->nphy_txiqlocal_bestc[5]); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, ++ 16, ++ &pi->nphy_txiqlocal_bestc[5]); ++ } ++ } ++} ++ ++void ++wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, ++ struct nphy_iq_comp *pcomp) ++{ ++ if (write) { ++ write_phy_reg(pi, 0x9a, pcomp->a0); ++ write_phy_reg(pi, 0x9b, pcomp->b0); ++ write_phy_reg(pi, 0x9c, pcomp->a1); ++ write_phy_reg(pi, 0x9d, pcomp->b1); ++ } else { ++ pcomp->a0 = read_phy_reg(pi, 0x9a); ++ pcomp->b0 = read_phy_reg(pi, 0x9b); ++ pcomp->a1 = read_phy_reg(pi, 0x9c); ++ pcomp->b1 = read_phy_reg(pi, 0x9d); ++ } ++} ++ ++void ++wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, ++ u16 num_samps, u8 wait_time, u8 wait_for_crs) ++{ ++ u8 core; ++ ++ write_phy_reg(pi, 0x12b, num_samps); ++ mod_phy_reg(pi, 0x12a, (0xff << 0), (wait_time << 0)); ++ mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqMode, ++ (wait_for_crs) ? NPHY_IqestCmd_iqMode : 0); ++ ++ mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqstart, NPHY_IqestCmd_iqstart); ++ ++ SPINWAIT(((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) != 0), ++ 10000); ++ if (WARN(read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart, ++ "HW error: rxiq est")) ++ return; ++ ++ if ((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) == 0) { ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ est[core].i_pwr = ++ (read_phy_reg(pi, ++ NPHY_IqestipwrAccHi(core)) << 16) ++ | read_phy_reg(pi, NPHY_IqestipwrAccLo(core)); ++ est[core].q_pwr = ++ (read_phy_reg(pi, ++ NPHY_IqestqpwrAccHi(core)) << 16) ++ | read_phy_reg(pi, NPHY_IqestqpwrAccLo(core)); ++ est[core].iq_prod = ++ (read_phy_reg(pi, ++ NPHY_IqestIqAccHi(core)) << 16) | ++ read_phy_reg(pi, NPHY_IqestIqAccLo(core)); ++ } ++ } ++} ++ ++#define CAL_RETRY_CNT 2 ++static void wlc_phy_calc_rx_iq_comp_nphy(struct brcms_phy *pi, u8 core_mask) ++{ ++ u8 curr_core; ++ struct phy_iq_est est[PHY_CORE_MAX]; ++ struct nphy_iq_comp old_comp, new_comp; ++ s32 iq = 0; ++ u32 ii = 0, qq = 0; ++ s16 iq_nbits, qq_nbits, brsh, arsh; ++ s32 a, b, temp; ++ int bcmerror = 0; ++ uint cal_retry = 0; ++ ++ if (core_mask == 0x0) ++ return; ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 0, &old_comp); ++ new_comp.a0 = new_comp.b0 = new_comp.a1 = new_comp.b1 = 0x0; ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp); ++ ++cal_try: ++ wlc_phy_rx_iq_est_nphy(pi, est, 0x4000, 32, 0); ++ ++ new_comp = old_comp; ++ ++ for (curr_core = 0; curr_core < pi->pubpi.phy_corenum; curr_core++) { ++ ++ if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) { ++ iq = est[curr_core].iq_prod; ++ ii = est[curr_core].i_pwr; ++ qq = est[curr_core].q_pwr; ++ } else if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) { ++ iq = est[curr_core].iq_prod; ++ ii = est[curr_core].i_pwr; ++ qq = est[curr_core].q_pwr; ++ } else { ++ continue; ++ } ++ ++ if ((ii + qq) < NPHY_MIN_RXIQ_PWR) { ++ bcmerror = -EBADE; ++ break; ++ } ++ ++ iq_nbits = wlc_phy_nbits(iq); ++ qq_nbits = wlc_phy_nbits(qq); ++ ++ arsh = 10 - (30 - iq_nbits); ++ if (arsh >= 0) { ++ a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); ++ temp = (s32) (ii >> arsh); ++ if (temp == 0) { ++ bcmerror = -EBADE; ++ break; ++ } ++ } else { ++ a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); ++ temp = (s32) (ii << -arsh); ++ if (temp == 0) { ++ bcmerror = -EBADE; ++ break; ++ } ++ } ++ ++ a /= temp; ++ ++ brsh = qq_nbits - 31 + 20; ++ if (brsh >= 0) { ++ b = (qq << (31 - qq_nbits)); ++ temp = (s32) (ii >> brsh); ++ if (temp == 0) { ++ bcmerror = -EBADE; ++ break; ++ } ++ } else { ++ b = (qq << (31 - qq_nbits)); ++ temp = (s32) (ii << -brsh); ++ if (temp == 0) { ++ bcmerror = -EBADE; ++ break; ++ } ++ } ++ b /= temp; ++ b -= a * a; ++ b = (s32) int_sqrt((unsigned long) b); ++ b -= (1 << 10); ++ ++ if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ new_comp.a0 = (s16) a & 0x3ff; ++ new_comp.b0 = (s16) b & 0x3ff; ++ } else { ++ ++ new_comp.a0 = (s16) b & 0x3ff; ++ new_comp.b0 = (s16) a & 0x3ff; ++ } ++ } ++ if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ new_comp.a1 = (s16) a & 0x3ff; ++ new_comp.b1 = (s16) b & 0x3ff; ++ } else { ++ ++ new_comp.a1 = (s16) b & 0x3ff; ++ new_comp.b1 = (s16) a & 0x3ff; ++ } ++ } ++ } ++ ++ if (bcmerror != 0) { ++ printk(KERN_DEBUG "%s: Failed, cnt = %d\n", __func__, ++ cal_retry); ++ ++ if (cal_retry < CAL_RETRY_CNT) { ++ cal_retry++; ++ goto cal_try; ++ } ++ ++ new_comp = old_comp; ++ } ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp); ++} ++ ++static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core) ++{ ++ u16 offtune_val; ++ u16 bias_g = 0; ++ u16 bias_a = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (rx_core == PHY_CORE_0) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP, ++ 0x3); ++ write_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN, ++ 0xaf); ++ ++ } else { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP, ++ 0x3); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN, ++ 0x7f); ++ } ++ ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP, ++ 0x3); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN, ++ 0xaf); ++ ++ } else { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN); ++ ++ write_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP, ++ 0x3); ++ write_radio_reg(pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN, ++ 0x7f); ++ } ++ } ++ ++ } else { ++ if (rx_core == PHY_CORE_0) { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX1); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX0); ++ ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[2] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RXSPARE2 | ++ RADIO_2056_RX0); ++ pi->tx_rx_cal_radio_saveregs[3] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TXSPARE2 | ++ RADIO_2056_TX1); ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_LNAA_MASTER ++ | RADIO_2056_RX0); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_MASTER ++ | RADIO_2056_RX0, 0x40); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TXSPARE2 | ++ RADIO_2056_TX1, bias_a); ++ ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXSPARE2 | ++ RADIO_2056_RX0, bias_a); ++ } else { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_LNAA_TUNE ++ | RADIO_2056_RX0); ++ ++ offtune_val = ++ (pi->tx_rx_cal_radio_saveregs ++ [2] & 0xF0) >> 8; ++ offtune_val = ++ (offtune_val <= 0x7) ? 0xF : 0; ++ ++ mod_radio_reg(pi, ++ RADIO_2056_RX_LNAA_TUNE | ++ RADIO_2056_RX0, 0xF0, ++ (offtune_val << 8)); ++ } ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX1, 0x9); ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX0, 0x9); ++ } else { ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX0); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX0, 0x40); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TXSPARE2 ++ | ++ RADIO_2056_TX1, bias_g); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_RXSPARE2 ++ | ++ RADIO_2056_RX0, bias_g); ++ ++ } else { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_TUNE ++ | RADIO_2056_RX0); ++ ++ offtune_val = ++ (pi-> ++ tx_rx_cal_radio_saveregs[2] & ++ 0xF0) >> 8; ++ offtune_val = ++ (offtune_val <= 0x7) ? 0xF : 0; ++ ++ mod_radio_reg(pi, ++ RADIO_2056_RX_LNAG_TUNE | ++ RADIO_2056_RX0, 0xF0, ++ (offtune_val << 8)); ++ } ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX1, 0x6); ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX0, 0x6); ++ } ++ ++ } else { ++ pi->tx_rx_cal_radio_saveregs[0] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX0); ++ pi->tx_rx_cal_radio_saveregs[1] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX1); ++ ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[2] = ++ read_radio_reg(pi, ++ RADIO_2056_RX_RXSPARE2 | ++ RADIO_2056_RX1); ++ pi->tx_rx_cal_radio_saveregs[3] = ++ read_radio_reg(pi, ++ RADIO_2056_TX_TXSPARE2 | ++ RADIO_2056_TX0); ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_MASTER ++ | RADIO_2056_RX1); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_MASTER | ++ RADIO_2056_RX1, 0x40); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TXSPARE2 ++ | ++ RADIO_2056_TX0, bias_a); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_RXSPARE2 ++ | ++ RADIO_2056_RX1, bias_a); ++ } else { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_TUNE ++ | RADIO_2056_RX1); ++ ++ offtune_val = ++ (pi-> ++ tx_rx_cal_radio_saveregs[2] & ++ 0xF0) >> 8; ++ offtune_val = ++ (offtune_val <= 0x7) ? 0xF : 0; ++ ++ mod_radio_reg(pi, ++ RADIO_2056_RX_LNAA_TUNE | ++ RADIO_2056_RX1, 0xF0, ++ (offtune_val << 8)); ++ } ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX0, 0x9); ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX1, 0x9); ++ } else { ++ if (pi->pubpi.radiorev >= 5) { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX1); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX1, 0x40); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_TX_TXSPARE2 ++ | ++ RADIO_2056_TX0, bias_g); ++ ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_RXSPARE2 ++ | ++ RADIO_2056_RX1, bias_g); ++ } else { ++ pi->tx_rx_cal_radio_saveregs[4] = ++ read_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_TUNE ++ | RADIO_2056_RX1); ++ ++ offtune_val = ++ (pi-> ++ tx_rx_cal_radio_saveregs[2] & ++ 0xF0) >> 8; ++ offtune_val = ++ (offtune_val <= 0x7) ? 0xF : 0; ++ ++ mod_radio_reg(pi, ++ RADIO_2056_RX_LNAG_TUNE | ++ RADIO_2056_RX1, 0xF0, ++ (offtune_val << 8)); ++ } ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX0, 0x6); ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX1, 0x6); ++ } ++ } ++ } ++} ++ ++static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core) ++{ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ if (rx_core == PHY_CORE_0) { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP, ++ pi-> ++ tx_rx_cal_radio_saveregs[0]); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN, ++ pi-> ++ tx_rx_cal_radio_saveregs[1]); ++ ++ } else { ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP, ++ pi-> ++ tx_rx_cal_radio_saveregs[0]); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN, ++ pi-> ++ tx_rx_cal_radio_saveregs[1]); ++ } ++ ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP, ++ pi-> ++ tx_rx_cal_radio_saveregs[0]); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN, ++ pi-> ++ tx_rx_cal_radio_saveregs[1]); ++ ++ } else { ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP, ++ pi-> ++ tx_rx_cal_radio_saveregs[0]); ++ write_radio_reg( ++ pi, ++ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN, ++ pi-> ++ tx_rx_cal_radio_saveregs[1]); ++ } ++ } ++ ++ } else { ++ if (rx_core == PHY_CORE_0) { ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX1, ++ pi->tx_rx_cal_radio_saveregs[0]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX0, ++ pi->tx_rx_cal_radio_saveregs[1]); ++ ++ if (pi->pubpi.radiorev >= 5) { ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXSPARE2 | ++ RADIO_2056_RX0, ++ pi-> ++ tx_rx_cal_radio_saveregs[2]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TXSPARE2 | ++ RADIO_2056_TX1, ++ pi-> ++ tx_rx_cal_radio_saveregs[3]); ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (pi->pubpi.radiorev >= 5) ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_MASTER ++ | RADIO_2056_RX0, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ else ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_TUNE ++ | RADIO_2056_RX0, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ } else { ++ if (pi->pubpi.radiorev >= 5) ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX0, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ else ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_TUNE ++ | RADIO_2056_RX0, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ } ++ ++ } else { ++ write_radio_reg(pi, ++ RADIO_2056_TX_RXIQCAL_TXMUX | ++ RADIO_2056_TX0, ++ pi->tx_rx_cal_radio_saveregs[0]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXIQCAL_RXMUX | ++ RADIO_2056_RX1, ++ pi->tx_rx_cal_radio_saveregs[1]); ++ ++ if (pi->pubpi.radiorev >= 5) { ++ write_radio_reg(pi, ++ RADIO_2056_RX_RXSPARE2 | ++ RADIO_2056_RX1, ++ pi-> ++ tx_rx_cal_radio_saveregs[2]); ++ ++ write_radio_reg(pi, ++ RADIO_2056_TX_TXSPARE2 | ++ RADIO_2056_TX0, ++ pi-> ++ tx_rx_cal_radio_saveregs[3]); ++ } ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (pi->pubpi.radiorev >= 5) ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_MASTER ++ | RADIO_2056_RX1, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ else ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAA_TUNE ++ | RADIO_2056_RX1, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ } else { ++ if (pi->pubpi.radiorev >= 5) ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_MASTER ++ | RADIO_2056_RX1, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ else ++ write_radio_reg( ++ pi, ++ RADIO_2056_RX_LNAG_TUNE ++ | RADIO_2056_RX1, ++ pi-> ++ tx_rx_cal_radio_saveregs ++ [4]); ++ } ++ } ++ } ++} ++ ++static void wlc_phy_rxcal_physetup_nphy(struct brcms_phy *pi, u8 rx_core) ++{ ++ u8 tx_core; ++ u16 rx_antval, tx_antval; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ tx_core = rx_core; ++ else ++ tx_core = (rx_core == PHY_CORE_0) ? 1 : 0; ++ ++ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa2); ++ pi->tx_rx_cal_phy_saveregs[1] = ++ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7); ++ pi->tx_rx_cal_phy_saveregs[2] = ++ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5); ++ pi->tx_rx_cal_phy_saveregs[3] = read_phy_reg(pi, 0x91); ++ pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x92); ++ pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x7a); ++ pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x7d); ++ pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0xe7); ++ pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0xec); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ pi->tx_rx_cal_phy_saveregs[11] = read_phy_reg(pi, 0x342); ++ pi->tx_rx_cal_phy_saveregs[12] = read_phy_reg(pi, 0x343); ++ pi->tx_rx_cal_phy_saveregs[13] = read_phy_reg(pi, 0x346); ++ pi->tx_rx_cal_phy_saveregs[14] = read_phy_reg(pi, 0x347); ++ } ++ ++ pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297); ++ pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b); ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 0), (0) << 0); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); ++ ++ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << (1 - rx_core)) << 12); ++ ++ } else { ++ ++ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12); ++ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); ++ mod_phy_reg(pi, 0xa2, (0xf << 4), (1 << rx_core) << 4); ++ mod_phy_reg(pi, 0xa2, (0xf << 8), (1 << rx_core) << 8); ++ } ++ ++ mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), (0x1 << 2), 0); ++ mod_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5, ++ (0x1 << 2), (0x1 << 2)); ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) { ++ mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), ++ (0x1 << 0) | (0x1 << 1), 0); ++ mod_phy_reg(pi, (rx_core == PHY_CORE_0) ? ++ 0x8f : 0xa5, ++ (0x1 << 0) | (0x1 << 1), (0x1 << 0) | (0x1 << 1)); ++ } ++ ++ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 0, ++ RADIO_MIMO_CORESEL_CORE1 | ++ RADIO_MIMO_CORESEL_CORE2); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), ++ 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID0); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID2); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ if (CHSPEC_IS40(pi->radio_chanspec)) ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 7), ++ 2, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ else ++ wlc_phy_rfctrl_override_nphy_rev7( ++ pi, ++ (0x1 << 7), ++ 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), ++ 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0, 0, ++ NPHY_REV7_RFCTRLOVERRIDE_ID1); ++ } else { ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 3, 0); ++ } ++ ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ 0x1, rx_core + 1); ++ } else { ++ ++ if (rx_core == PHY_CORE_0) { ++ rx_antval = 0x1; ++ tx_antval = 0x8; ++ } else { ++ rx_antval = 0x4; ++ tx_antval = 0x2; ++ } ++ ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ rx_antval, rx_core + 1); ++ wlc_phy_rfctrlintc_override_nphy(pi, ++ NPHY_RfctrlIntc_override_TRSW, ++ tx_antval, tx_core + 1); ++ } ++} ++ ++static void wlc_phy_rxcal_phycleanup_nphy(struct brcms_phy *pi, u8 rx_core) ++{ ++ ++ write_phy_reg(pi, 0xa2, pi->tx_rx_cal_phy_saveregs[0]); ++ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7, ++ pi->tx_rx_cal_phy_saveregs[1]); ++ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5, ++ pi->tx_rx_cal_phy_saveregs[2]); ++ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[3]); ++ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[4]); ++ ++ write_phy_reg(pi, 0x7a, pi->tx_rx_cal_phy_saveregs[5]); ++ write_phy_reg(pi, 0x7d, pi->tx_rx_cal_phy_saveregs[6]); ++ write_phy_reg(pi, 0xe7, pi->tx_rx_cal_phy_saveregs[7]); ++ write_phy_reg(pi, 0xec, pi->tx_rx_cal_phy_saveregs[8]); ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ write_phy_reg(pi, 0x342, pi->tx_rx_cal_phy_saveregs[11]); ++ write_phy_reg(pi, 0x343, pi->tx_rx_cal_phy_saveregs[12]); ++ write_phy_reg(pi, 0x346, pi->tx_rx_cal_phy_saveregs[13]); ++ write_phy_reg(pi, 0x347, pi->tx_rx_cal_phy_saveregs[14]); ++ } ++ ++ write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]); ++ write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]); ++} ++ ++static void ++wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core, ++ u16 *rxgain, u8 cal_type) ++{ ++ ++ u16 num_samps; ++ struct phy_iq_est est[PHY_CORE_MAX]; ++ u8 tx_core; ++ struct nphy_iq_comp save_comp, zero_comp; ++ u32 i_pwr, q_pwr, curr_pwr, optim_pwr = 0, prev_pwr = 0, ++ thresh_pwr = 10000; ++ s16 desired_log2_pwr, actual_log2_pwr, delta_pwr; ++ bool gainctrl_done = false; ++ u8 mix_tia_gain = 3; ++ s8 optim_gaintbl_index = 0, prev_gaintbl_index = 0; ++ s8 curr_gaintbl_index = 3; ++ u8 gainctrl_dirn = NPHY_RXCAL_GAIN_INIT; ++ const struct nphy_ipa_txrxgain *nphy_rxcal_gaintbl; ++ u16 hpvga, lpf_biq1, lpf_biq0, lna2, lna1; ++ int fine_gain_idx; ++ s8 txpwrindex; ++ u16 nphy_rxcal_txgain[2]; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ tx_core = rx_core; ++ else ++ tx_core = 1 - rx_core; ++ ++ num_samps = 1024; ++ desired_log2_pwr = (cal_type == 0) ? 13 : 13; ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 0, &save_comp); ++ zero_comp.a0 = zero_comp.b0 = zero_comp.a1 = zero_comp.b1 = 0x0; ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &zero_comp); ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ mix_tia_gain = 3; ++ else if (NREV_GE(pi->pubpi.phy_rev, 4)) ++ mix_tia_gain = 4; ++ else ++ mix_tia_gain = 6; ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz_rev7; ++ else ++ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz; ++ } else { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz_rev7; ++ else ++ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz; ++ } ++ ++ do { ++ ++ hpvga = (NREV_GE(pi->pubpi.phy_rev, 7)) ? ++ 0 : nphy_rxcal_gaintbl[curr_gaintbl_index].hpvga; ++ lpf_biq1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq1; ++ lpf_biq0 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq0; ++ lna2 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna2; ++ lna1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna1; ++ txpwrindex = nphy_rxcal_gaintbl[curr_gaintbl_index].txpwrindex; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_rxgain, ++ ((lpf_biq1 << 12) | ++ (lpf_biq0 << 8) | ++ (mix_tia_gain << 4) | (lna2 << 2) ++ | lna1), 0x3, 0); ++ else ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), ++ ((hpvga << 12) | ++ (lpf_biq1 << 10) | ++ (lpf_biq0 << 8) | ++ (mix_tia_gain << 4) | ++ (lna2 << 2) | lna1), 0x3, ++ 0); ++ ++ pi->nphy_rxcal_pwr_idx[tx_core] = txpwrindex; ++ ++ if (txpwrindex == -1) { ++ nphy_rxcal_txgain[0] = 0x8ff0 | pi->nphy_gmval; ++ nphy_rxcal_txgain[1] = 0x8ff0 | pi->nphy_gmval; ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, ++ 2, 0x110, 16, ++ nphy_rxcal_txgain); ++ } else { ++ wlc_phy_txpwr_index_nphy(pi, tx_core + 1, txpwrindex, ++ false); ++ } ++ ++ wlc_phy_tx_tone_nphy(pi, (CHSPEC_IS40(pi->radio_chanspec)) ? ++ NPHY_RXCAL_TONEFREQ_40MHz : ++ NPHY_RXCAL_TONEFREQ_20MHz, ++ NPHY_RXCAL_TONEAMP, 0, cal_type, false); ++ ++ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); ++ i_pwr = (est[rx_core].i_pwr + num_samps / 2) / num_samps; ++ q_pwr = (est[rx_core].q_pwr + num_samps / 2) / num_samps; ++ curr_pwr = i_pwr + q_pwr; ++ ++ switch (gainctrl_dirn) { ++ case NPHY_RXCAL_GAIN_INIT: ++ if (curr_pwr > thresh_pwr) { ++ gainctrl_dirn = NPHY_RXCAL_GAIN_DOWN; ++ prev_gaintbl_index = curr_gaintbl_index; ++ curr_gaintbl_index--; ++ } else { ++ gainctrl_dirn = NPHY_RXCAL_GAIN_UP; ++ prev_gaintbl_index = curr_gaintbl_index; ++ curr_gaintbl_index++; ++ } ++ break; ++ ++ case NPHY_RXCAL_GAIN_UP: ++ if (curr_pwr > thresh_pwr) { ++ gainctrl_done = true; ++ optim_pwr = prev_pwr; ++ optim_gaintbl_index = prev_gaintbl_index; ++ } else { ++ prev_gaintbl_index = curr_gaintbl_index; ++ curr_gaintbl_index++; ++ } ++ break; ++ ++ case NPHY_RXCAL_GAIN_DOWN: ++ if (curr_pwr > thresh_pwr) { ++ prev_gaintbl_index = curr_gaintbl_index; ++ curr_gaintbl_index--; ++ } else { ++ gainctrl_done = true; ++ optim_pwr = curr_pwr; ++ optim_gaintbl_index = curr_gaintbl_index; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if ((curr_gaintbl_index < 0) || ++ (curr_gaintbl_index > NPHY_IPA_RXCAL_MAXGAININDEX)) { ++ gainctrl_done = true; ++ optim_pwr = curr_pwr; ++ optim_gaintbl_index = prev_gaintbl_index; ++ } else { ++ prev_pwr = curr_pwr; ++ } ++ ++ wlc_phy_stopplayback_nphy(pi); ++ } while (!gainctrl_done); ++ ++ hpvga = nphy_rxcal_gaintbl[optim_gaintbl_index].hpvga; ++ lpf_biq1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq1; ++ lpf_biq0 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq0; ++ lna2 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna2; ++ lna1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna1; ++ txpwrindex = nphy_rxcal_gaintbl[optim_gaintbl_index].txpwrindex; ++ ++ actual_log2_pwr = wlc_phy_nbits(optim_pwr); ++ delta_pwr = desired_log2_pwr - actual_log2_pwr; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ fine_gain_idx = (int)lpf_biq1 + delta_pwr; ++ ++ if (fine_gain_idx + (int)lpf_biq0 > 10) ++ lpf_biq1 = 10 - lpf_biq0; ++ else ++ lpf_biq1 = (u16) max(fine_gain_idx, 0); ++ ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_rxgain, ++ ((lpf_biq1 << 12) | ++ (lpf_biq0 << 8) | ++ (mix_tia_gain << 4) | ++ (lna2 << 2) | lna1), 0x3, ++ 0); ++ } else { ++ hpvga = (u16) max(min(((int)hpvga) + delta_pwr, 10), 0); ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), ++ ((hpvga << 12) | ++ (lpf_biq1 << 10) | ++ (lpf_biq0 << 8) | ++ (mix_tia_gain << 4) | ++ (lna2 << 2) | ++ lna1), 0x3, 0); ++ } ++ ++ if (rxgain != NULL) { ++ *rxgain++ = lna1; ++ *rxgain++ = lna2; ++ *rxgain++ = mix_tia_gain; ++ *rxgain++ = lpf_biq0; ++ *rxgain++ = lpf_biq1; ++ *rxgain = hpvga; ++ } ++ ++ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &save_comp); ++} ++ ++static void ++wlc_phy_rxcal_gainctrl_nphy(struct brcms_phy *pi, u8 rx_core, u16 *rxgain, ++ u8 cal_type) ++{ ++ wlc_phy_rxcal_gainctrl_nphy_rev5(pi, rx_core, rxgain, cal_type); ++} ++ ++static u8 ++wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type) ++{ ++ u32 target_bws[2] = { 9500, 21000 }; ++ u32 ref_tones[2] = { 3000, 6000 }; ++ u32 target_bw, ref_tone; ++ ++ u32 target_pwr_ratios[2] = { 28606, 18468 }; ++ u32 target_pwr_ratio, pwr_ratio, last_pwr_ratio = 0; ++ ++ u16 start_rccal_ovr_val = 128; ++ u16 txlpf_rccal_lpc_ovr_val = 128; ++ u16 rxlpf_rccal_hpc_ovr_val = 159; ++ ++ u16 orig_txlpf_rccal_lpc_ovr_val; ++ u16 orig_rxlpf_rccal_hpc_ovr_val; ++ u16 radio_addr_offset_rx; ++ u16 radio_addr_offset_tx; ++ u16 orig_dcBypass; ++ u16 orig_RxStrnFilt40Num[6]; ++ u16 orig_RxStrnFilt40Den[4]; ++ u16 orig_rfctrloverride[2]; ++ u16 orig_rfctrlauxreg[2]; ++ u16 orig_rfctrlrssiothers; ++ u16 tx_lpf_bw = 4; ++ ++ u16 rx_lpf_bw, rx_lpf_bws[2] = { 2, 4 }; ++ u16 lpf_hpc = 7, hpvga_hpc = 7; ++ ++ s8 rccal_stepsize; ++ u16 rccal_val, last_rccal_val = 0, best_rccal_val = 0; ++ u32 ref_iq_vals = 0, target_iq_vals = 0; ++ u16 num_samps, log_num_samps = 10; ++ struct phy_iq_est est[PHY_CORE_MAX]; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ return 0; ++ ++ num_samps = (1 << log_num_samps); ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) { ++ target_bw = target_bws[1]; ++ target_pwr_ratio = target_pwr_ratios[1]; ++ ref_tone = ref_tones[1]; ++ rx_lpf_bw = rx_lpf_bws[1]; ++ } else { ++ target_bw = target_bws[0]; ++ target_pwr_ratio = target_pwr_ratios[0]; ++ ref_tone = ref_tones[0]; ++ rx_lpf_bw = rx_lpf_bws[0]; ++ } ++ ++ if (core_idx == 0) { ++ radio_addr_offset_rx = RADIO_2056_RX0; ++ radio_addr_offset_tx = ++ (loopback_type == 0) ? RADIO_2056_TX0 : RADIO_2056_TX1; ++ } else { ++ radio_addr_offset_rx = RADIO_2056_RX1; ++ radio_addr_offset_tx = ++ (loopback_type == 0) ? RADIO_2056_TX1 : RADIO_2056_TX0; ++ } ++ ++ orig_txlpf_rccal_lpc_ovr_val = ++ read_radio_reg(pi, ++ (RADIO_2056_TX_TXLPF_RCCAL | ++ radio_addr_offset_tx)); ++ orig_rxlpf_rccal_hpc_ovr_val = ++ read_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_HPC | ++ radio_addr_offset_rx)); ++ ++ orig_dcBypass = ((read_phy_reg(pi, 0x48) >> 8) & 1); ++ ++ orig_RxStrnFilt40Num[0] = read_phy_reg(pi, 0x267); ++ orig_RxStrnFilt40Num[1] = read_phy_reg(pi, 0x268); ++ orig_RxStrnFilt40Num[2] = read_phy_reg(pi, 0x269); ++ orig_RxStrnFilt40Den[0] = read_phy_reg(pi, 0x26a); ++ orig_RxStrnFilt40Den[1] = read_phy_reg(pi, 0x26b); ++ orig_RxStrnFilt40Num[3] = read_phy_reg(pi, 0x26c); ++ orig_RxStrnFilt40Num[4] = read_phy_reg(pi, 0x26d); ++ orig_RxStrnFilt40Num[5] = read_phy_reg(pi, 0x26e); ++ orig_RxStrnFilt40Den[2] = read_phy_reg(pi, 0x26f); ++ orig_RxStrnFilt40Den[3] = read_phy_reg(pi, 0x270); ++ ++ orig_rfctrloverride[0] = read_phy_reg(pi, 0xe7); ++ orig_rfctrloverride[1] = read_phy_reg(pi, 0xec); ++ orig_rfctrlauxreg[0] = read_phy_reg(pi, 0xf8); ++ orig_rfctrlauxreg[1] = read_phy_reg(pi, 0xfa); ++ orig_rfctrlrssiothers = read_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d); ++ ++ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx), ++ txlpf_rccal_lpc_ovr_val); ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx), ++ rxlpf_rccal_hpc_ovr_val); ++ ++ mod_phy_reg(pi, 0x48, (0x1 << 8), (0x1 << 8)); ++ ++ write_phy_reg(pi, 0x267, 0x02d4); ++ write_phy_reg(pi, 0x268, 0x0000); ++ write_phy_reg(pi, 0x269, 0x0000); ++ write_phy_reg(pi, 0x26a, 0x0000); ++ write_phy_reg(pi, 0x26b, 0x0000); ++ write_phy_reg(pi, 0x26c, 0x02d4); ++ write_phy_reg(pi, 0x26d, 0x0000); ++ write_phy_reg(pi, 0x26e, 0x0000); ++ write_phy_reg(pi, 0x26f, 0x0000); ++ write_phy_reg(pi, 0x270, 0x0000); ++ ++ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 8)); ++ or_phy_reg(pi, (core_idx == 0) ? 0xec : 0xe7, (0x1 << 15)); ++ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 9)); ++ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 10)); ++ ++ mod_phy_reg(pi, (core_idx == 0) ? 0xfa : 0xf8, ++ (0x7 << 10), (tx_lpf_bw << 10)); ++ mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa, ++ (0x7 << 0), (hpvga_hpc << 0)); ++ mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa, ++ (0x7 << 4), (lpf_hpc << 4)); ++ mod_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d, ++ (0x7 << 8), (rx_lpf_bw << 8)); ++ ++ rccal_stepsize = 16; ++ rccal_val = start_rccal_ovr_val + rccal_stepsize; ++ ++ while (rccal_stepsize >= 0) { ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_LPC | ++ radio_addr_offset_rx), rccal_val); ++ ++ if (rccal_stepsize == 16) { ++ ++ wlc_phy_tx_tone_nphy(pi, ref_tone, NPHY_RXCAL_TONEAMP, ++ 0, 1, false); ++ udelay(2); ++ ++ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); ++ ++ if (core_idx == 0) ++ ref_iq_vals = ++ max_t(u32, (est[0].i_pwr + ++ est[0].q_pwr) >> ++ (log_num_samps + 1), ++ 1); ++ else ++ ref_iq_vals = ++ max_t(u32, (est[1].i_pwr + ++ est[1].q_pwr) >> ++ (log_num_samps + 1), ++ 1); ++ ++ wlc_phy_tx_tone_nphy(pi, target_bw, NPHY_RXCAL_TONEAMP, ++ 0, 1, false); ++ udelay(2); ++ } ++ ++ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); ++ ++ if (core_idx == 0) ++ target_iq_vals = (est[0].i_pwr + est[0].q_pwr) >> ++ (log_num_samps + 1); ++ else ++ target_iq_vals = ++ (est[1].i_pwr + ++ est[1].q_pwr) >> (log_num_samps + 1); ++ ++ pwr_ratio = (uint) ((target_iq_vals << 16) / ref_iq_vals); ++ ++ if (rccal_stepsize == 0) ++ rccal_stepsize--; ++ else if (rccal_stepsize == 1) { ++ last_rccal_val = rccal_val; ++ rccal_val += (pwr_ratio > target_pwr_ratio) ? 1 : -1; ++ last_pwr_ratio = pwr_ratio; ++ rccal_stepsize--; ++ } else { ++ rccal_stepsize = (rccal_stepsize >> 1); ++ rccal_val += ((pwr_ratio > target_pwr_ratio) ? ++ rccal_stepsize : (-rccal_stepsize)); ++ } ++ ++ if (rccal_stepsize == -1) { ++ best_rccal_val = ++ (abs((int)last_pwr_ratio - ++ (int)target_pwr_ratio) < ++ abs((int)pwr_ratio - ++ (int)target_pwr_ratio)) ? last_rccal_val : ++ rccal_val; ++ ++ if (CHSPEC_IS40(pi->radio_chanspec)) { ++ if ((best_rccal_val > 140) ++ || (best_rccal_val < 135)) ++ best_rccal_val = 138; ++ } else { ++ if ((best_rccal_val > 142) ++ || (best_rccal_val < 137)) ++ best_rccal_val = 140; ++ } ++ ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_LPC | ++ radio_addr_offset_rx), best_rccal_val); ++ } ++ } ++ ++ wlc_phy_stopplayback_nphy(pi); ++ ++ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx), ++ orig_txlpf_rccal_lpc_ovr_val); ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx), ++ orig_rxlpf_rccal_hpc_ovr_val); ++ ++ mod_phy_reg(pi, 0x48, (0x1 << 8), (orig_dcBypass << 8)); ++ ++ write_phy_reg(pi, 0x267, orig_RxStrnFilt40Num[0]); ++ write_phy_reg(pi, 0x268, orig_RxStrnFilt40Num[1]); ++ write_phy_reg(pi, 0x269, orig_RxStrnFilt40Num[2]); ++ write_phy_reg(pi, 0x26a, orig_RxStrnFilt40Den[0]); ++ write_phy_reg(pi, 0x26b, orig_RxStrnFilt40Den[1]); ++ write_phy_reg(pi, 0x26c, orig_RxStrnFilt40Num[3]); ++ write_phy_reg(pi, 0x26d, orig_RxStrnFilt40Num[4]); ++ write_phy_reg(pi, 0x26e, orig_RxStrnFilt40Num[5]); ++ write_phy_reg(pi, 0x26f, orig_RxStrnFilt40Den[2]); ++ write_phy_reg(pi, 0x270, orig_RxStrnFilt40Den[3]); ++ ++ write_phy_reg(pi, 0xe7, orig_rfctrloverride[0]); ++ write_phy_reg(pi, 0xec, orig_rfctrloverride[1]); ++ write_phy_reg(pi, 0xf8, orig_rfctrlauxreg[0]); ++ write_phy_reg(pi, 0xfa, orig_rfctrlauxreg[1]); ++ write_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d, orig_rfctrlrssiothers); ++ ++ pi->nphy_anarxlpf_adjusted = false; ++ ++ return best_rccal_val - 0x80; ++} ++ ++#define WAIT_FOR_SCOPE 4000 ++static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi, ++ struct nphy_txgains target_gain, ++ u8 cal_type, bool debug) ++{ ++ u16 orig_BBConfig; ++ u8 core_no, rx_core; ++ u8 best_rccal[2]; ++ u16 gain_save[2]; ++ u16 cal_gain[2]; ++ struct nphy_iqcal_params cal_params[2]; ++ u8 rxcore_state; ++ s8 rxlpf_rccal_hpc, txlpf_rccal_lpc; ++ s8 txlpf_idac; ++ bool phyhang_avoid_state = false; ++ bool skip_rxiqcal = false; ++ ++ orig_BBConfig = read_phy_reg(pi, 0x01); ++ mod_phy_reg(pi, 0x01, (0x1 << 15), 0); ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 4)) { ++ phyhang_avoid_state = pi->phyhang_avoid; ++ pi->phyhang_avoid = false; ++ } ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); ++ ++ for (core_no = 0; core_no <= 1; core_no++) { ++ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, ++ &cal_params[core_no]); ++ cal_gain[core_no] = cal_params[core_no].cal_gain; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); ++ ++ rxcore_state = wlc_phy_rxcore_getstate_nphy( ++ (struct brcms_phy_pub *) pi); ++ ++ for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) { ++ ++ skip_rxiqcal = ++ ((rxcore_state & (1 << rx_core)) == 0) ? true : false; ++ ++ wlc_phy_rxcal_physetup_nphy(pi, rx_core); ++ ++ wlc_phy_rxcal_radio_setup_nphy(pi, rx_core); ++ ++ if ((!skip_rxiqcal) && ((cal_type == 0) || (cal_type == 2))) { ++ ++ wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, 0); ++ ++ wlc_phy_tx_tone_nphy(pi, ++ (CHSPEC_IS40( ++ pi->radio_chanspec)) ? ++ NPHY_RXCAL_TONEFREQ_40MHz : ++ NPHY_RXCAL_TONEFREQ_20MHz, ++ NPHY_RXCAL_TONEAMP, 0, cal_type, ++ false); ++ ++ if (debug) ++ mdelay(WAIT_FOR_SCOPE); ++ ++ wlc_phy_calc_rx_iq_comp_nphy(pi, rx_core + 1); ++ wlc_phy_stopplayback_nphy(pi); ++ } ++ ++ if (((cal_type == 1) || (cal_type == 2)) ++ && NREV_LT(pi->pubpi.phy_rev, 7)) { ++ ++ if (rx_core == PHY_CORE_1) { ++ ++ if (rxcore_state == 1) ++ wlc_phy_rxcore_setstate_nphy( ++ (struct brcms_phy_pub *) pi, 3); ++ ++ wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, ++ 1); ++ ++ best_rccal[rx_core] = ++ wlc_phy_rc_sweep_nphy(pi, rx_core, 1); ++ pi->nphy_rccal_value = best_rccal[rx_core]; ++ ++ if (rxcore_state == 1) ++ wlc_phy_rxcore_setstate_nphy( ++ (struct brcms_phy_pub *) pi, ++ rxcore_state); ++ } ++ } ++ ++ wlc_phy_rxcal_radio_cleanup_nphy(pi, rx_core); ++ ++ wlc_phy_rxcal_phycleanup_nphy(pi, rx_core); ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ } ++ ++ if ((cal_type == 1) || (cal_type == 2)) { ++ ++ best_rccal[0] = best_rccal[1]; ++ write_radio_reg(pi, ++ (RADIO_2056_RX_RXLPF_RCCAL_LPC | ++ RADIO_2056_RX0), (best_rccal[0] | 0x80)); ++ ++ for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) { ++ rxlpf_rccal_hpc = ++ (((int)best_rccal[rx_core] - 12) >> 1) + 10; ++ txlpf_rccal_lpc = ((int)best_rccal[rx_core] - 12) + 10; ++ ++ if (PHY_IPA(pi)) { ++ txlpf_rccal_lpc += ++ (pi->bw == WL_CHANSPEC_BW_40) ? 24 : 12; ++ txlpf_idac = (pi->bw == WL_CHANSPEC_BW_40) ? ++ 0x0e : 0x13; ++ WRITE_RADIO_REG2(pi, RADIO_2056, TX, rx_core, ++ TXLPF_IDAC_4, txlpf_idac); ++ } ++ ++ rxlpf_rccal_hpc = max(min_t(u8, rxlpf_rccal_hpc, 31), ++ 0); ++ txlpf_rccal_lpc = max(min_t(u8, txlpf_rccal_lpc, 31), ++ 0); ++ ++ write_radio_reg(pi, (RADIO_2056_RX_RXLPF_RCCAL_HPC | ++ ((rx_core == ++ PHY_CORE_0) ? RADIO_2056_RX0 : ++ RADIO_2056_RX1)), ++ (rxlpf_rccal_hpc | 0x80)); ++ ++ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | ++ ((rx_core == ++ PHY_CORE_0) ? RADIO_2056_TX0 : ++ RADIO_2056_TX1)), ++ (txlpf_rccal_lpc | 0x80)); ++ } ++ } ++ ++ write_phy_reg(pi, 0x01, orig_BBConfig); ++ ++ wlc_phy_resetcca_nphy(pi); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ wlc_phy_rfctrl_override_1tomany_nphy( ++ pi, ++ NPHY_REV7_RfctrlOverride_cmd_rxgain, ++ 0, 0x3, 1); ++ else ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1); ++ ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ gain_save); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 4)) ++ pi->phyhang_avoid = phyhang_avoid_state; ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ return 0; ++} ++ ++static int ++wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi, ++ struct nphy_txgains target_gain, bool debug) ++{ ++ struct phy_iq_est est[PHY_CORE_MAX]; ++ u8 core_num, rx_core, tx_core; ++ u16 lna_vals[] = { 0x3, 0x3, 0x1 }; ++ u16 hpf1_vals[] = { 0x7, 0x2, 0x0 }; ++ u16 hpf2_vals[] = { 0x2, 0x0, 0x0 }; ++ s16 curr_hpf1, curr_hpf2, curr_hpf, curr_lna; ++ s16 desired_log2_pwr, actual_log2_pwr, hpf_change; ++ u16 orig_RfseqCoreActv, orig_AfectrlCore, orig_AfectrlOverride; ++ u16 orig_RfctrlIntcRx, orig_RfctrlIntcTx; ++ u16 num_samps; ++ u32 i_pwr, q_pwr, tot_pwr[3]; ++ u8 gain_pass, use_hpf_num; ++ u16 mask, val1, val2; ++ u16 core_no; ++ u16 gain_save[2]; ++ u16 cal_gain[2]; ++ struct nphy_iqcal_params cal_params[2]; ++ u8 phy_bw; ++ int bcmerror = 0; ++ bool first_playtone = true; ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ wlc_phy_reapply_txcal_coeffs_nphy(pi); ++ ++ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); ++ ++ for (core_no = 0; core_no <= 1; core_no++) { ++ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, ++ &cal_params[core_no]); ++ cal_gain[core_no] = cal_params[core_no].cal_gain; ++ } ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); ++ ++ num_samps = 1024; ++ desired_log2_pwr = 13; ++ ++ for (core_num = 0; core_num < 2; core_num++) { ++ ++ rx_core = core_num; ++ tx_core = 1 - core_num; ++ ++ orig_RfseqCoreActv = read_phy_reg(pi, 0xa2); ++ orig_AfectrlCore = read_phy_reg(pi, (rx_core == PHY_CORE_0) ? ++ 0xa6 : 0xa7); ++ orig_AfectrlOverride = read_phy_reg(pi, 0xa5); ++ orig_RfctrlIntcRx = read_phy_reg(pi, (rx_core == PHY_CORE_0) ? ++ 0x91 : 0x92); ++ orig_RfctrlIntcTx = read_phy_reg(pi, (tx_core == PHY_CORE_0) ? ++ 0x91 : 0x92); ++ ++ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12); ++ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); ++ ++ or_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), ++ ((0x1 << 1) | (0x1 << 2))); ++ or_phy_reg(pi, 0xa5, ((0x1 << 1) | (0x1 << 2))); ++ ++ if (((pi->nphy_rxcalparams) & 0xff000000)) ++ write_phy_reg(pi, ++ (rx_core == PHY_CORE_0) ? 0x91 : 0x92, ++ (CHSPEC_IS5G(pi->radio_chanspec) ? ++ 0x140 : 0x110)); ++ else ++ write_phy_reg(pi, ++ (rx_core == PHY_CORE_0) ? 0x91 : 0x92, ++ (CHSPEC_IS5G(pi->radio_chanspec) ? ++ 0x180 : 0x120)); ++ ++ write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : 0x92, ++ (CHSPEC_IS5G(pi->radio_chanspec) ? 0x148 : ++ 0x114)); ++ ++ mask = RADIO_2055_COUPLE_RX_MASK | RADIO_2055_COUPLE_TX_MASK; ++ if (rx_core == PHY_CORE_0) { ++ val1 = RADIO_2055_COUPLE_RX_MASK; ++ val2 = RADIO_2055_COUPLE_TX_MASK; ++ } else { ++ val1 = RADIO_2055_COUPLE_TX_MASK; ++ val2 = RADIO_2055_COUPLE_RX_MASK; ++ } ++ ++ if ((pi->nphy_rxcalparams & 0x10000)) { ++ mod_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, mask, ++ val1); ++ mod_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, mask, ++ val2); ++ } ++ ++ for (gain_pass = 0; gain_pass < 4; gain_pass++) { ++ ++ if (debug) ++ mdelay(WAIT_FOR_SCOPE); ++ ++ if (gain_pass < 3) { ++ curr_lna = lna_vals[gain_pass]; ++ curr_hpf1 = hpf1_vals[gain_pass]; ++ curr_hpf2 = hpf2_vals[gain_pass]; ++ } else { ++ ++ if (tot_pwr[1] > 10000) { ++ curr_lna = lna_vals[2]; ++ curr_hpf1 = hpf1_vals[2]; ++ curr_hpf2 = hpf2_vals[2]; ++ use_hpf_num = 1; ++ curr_hpf = curr_hpf1; ++ actual_log2_pwr = ++ wlc_phy_nbits(tot_pwr[2]); ++ } else { ++ if (tot_pwr[0] > 10000) { ++ curr_lna = lna_vals[1]; ++ curr_hpf1 = hpf1_vals[1]; ++ curr_hpf2 = hpf2_vals[1]; ++ use_hpf_num = 1; ++ curr_hpf = curr_hpf1; ++ actual_log2_pwr = ++ wlc_phy_nbits( ++ tot_pwr[1]); ++ } else { ++ curr_lna = lna_vals[0]; ++ curr_hpf1 = hpf1_vals[0]; ++ curr_hpf2 = hpf2_vals[0]; ++ use_hpf_num = 2; ++ curr_hpf = curr_hpf2; ++ actual_log2_pwr = ++ wlc_phy_nbits( ++ tot_pwr[0]); ++ } ++ } ++ ++ hpf_change = desired_log2_pwr - actual_log2_pwr; ++ curr_hpf += hpf_change; ++ curr_hpf = max(min_t(u16, curr_hpf, 10), 0); ++ if (use_hpf_num == 1) ++ curr_hpf1 = curr_hpf; ++ else ++ curr_hpf2 = curr_hpf; ++ } ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10), ++ ((curr_hpf2 << 8) | ++ (curr_hpf1 << 4) | ++ (curr_lna << 2)), 0x3, 0); ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ ++ wlc_phy_stopplayback_nphy(pi); ++ ++ if (first_playtone) { ++ bcmerror = wlc_phy_tx_tone_nphy(pi, 4000, ++ (u16) (pi->nphy_rxcalparams & ++ 0xffff), 0, 0, true); ++ first_playtone = false; ++ } else { ++ phy_bw = (CHSPEC_IS40(pi->radio_chanspec)) ? ++ 40 : 20; ++ wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff, ++ 0, 0, 0, true); ++ } ++ ++ if (bcmerror == 0) { ++ if (gain_pass < 3) { ++ ++ wlc_phy_rx_iq_est_nphy(pi, est, ++ num_samps, 32, ++ 0); ++ i_pwr = (est[rx_core].i_pwr + ++ num_samps / 2) / num_samps; ++ q_pwr = (est[rx_core].q_pwr + ++ num_samps / 2) / num_samps; ++ tot_pwr[gain_pass] = i_pwr + q_pwr; ++ } else { ++ ++ wlc_phy_calc_rx_iq_comp_nphy(pi, ++ (1 << ++ rx_core)); ++ } ++ ++ wlc_phy_stopplayback_nphy(pi); ++ } ++ ++ if (bcmerror != 0) ++ break; ++ } ++ ++ and_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, ~mask); ++ and_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, ~mask); ++ ++ write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : ++ 0x92, orig_RfctrlIntcTx); ++ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x91 : ++ 0x92, orig_RfctrlIntcRx); ++ write_phy_reg(pi, 0xa5, orig_AfectrlOverride); ++ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : ++ 0xa7, orig_AfectrlCore); ++ write_phy_reg(pi, 0xa2, orig_RfseqCoreActv); ++ ++ if (bcmerror != 0) ++ break; ++ } ++ ++ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10), 0, 0x3, 1); ++ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, ++ gain_save); ++ ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ ++ return bcmerror; ++} ++ ++int ++wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, ++ u8 cal_type, bool debug) ++{ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ cal_type = 0; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ return wlc_phy_cal_rxiq_nphy_rev3(pi, target_gain, cal_type, ++ debug); ++ else ++ return wlc_phy_cal_rxiq_nphy_rev2(pi, target_gain, debug); ++} ++ ++void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi) ++{ ++ uint core; ++ u32 txgain; ++ u16 rad_gain, dac_gain, bbmult, m1m2; ++ u8 txpi[2], chan_freq_range; ++ s32 rfpwr_offset; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ if (pi->sh->sromrev < 4) { ++ txpi[0] = txpi[1] = 72; ++ } else { ++ ++ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0); ++ switch (chan_freq_range) { ++ case WL_CHAN_FREQ_RANGE_2G: ++ txpi[0] = pi->nphy_txpid2g[0]; ++ txpi[1] = pi->nphy_txpid2g[1]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GL: ++ txpi[0] = pi->nphy_txpid5gl[0]; ++ txpi[1] = pi->nphy_txpid5gl[1]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GM: ++ txpi[0] = pi->nphy_txpid5g[0]; ++ txpi[1] = pi->nphy_txpid5g[1]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GH: ++ txpi[0] = pi->nphy_txpid5gh[0]; ++ txpi[1] = pi->nphy_txpid5gh[1]; ++ break; ++ default: ++ txpi[0] = txpi[1] = 91; ++ break; ++ } ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) ++ txpi[0] = txpi[1] = 30; ++ else if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ txpi[0] = txpi[1] = 40; ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 7)) { ++ ++ if ((txpi[0] < 40) || (txpi[0] > 100) || ++ (txpi[1] < 40) || (txpi[1] > 100)) ++ txpi[0] = txpi[1] = 91; ++ } ++ ++ pi->nphy_txpwrindex[PHY_CORE_0].index_internal = txpi[0]; ++ pi->nphy_txpwrindex[PHY_CORE_1].index_internal = txpi[1]; ++ pi->nphy_txpwrindex[PHY_CORE_0].index_internal_save = txpi[0]; ++ pi->nphy_txpwrindex[PHY_CORE_1].index_internal_save = txpi[1]; ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ uint phyrev = pi->pubpi.phy_rev; ++ ++ if (NREV_GE(phyrev, 3)) { ++ if (PHY_IPA(pi)) { ++ u32 *tx_gaintbl = ++ wlc_phy_get_ipa_gaintbl_nphy(pi); ++ txgain = tx_gaintbl[txpi[core]]; ++ } else { ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_IS(phyrev, 3)) { ++ txgain = ++ nphy_tpc_5GHz_txgain_rev3 ++ [txpi[core]]; ++ } else if (NREV_IS(phyrev, 4)) { ++ txgain = ( ++ pi->srom_fem5g.extpagain == ++ 3) ? ++ nphy_tpc_5GHz_txgain_HiPwrEPA ++ [txpi[core]] : ++ nphy_tpc_5GHz_txgain_rev4 ++ [txpi[core]]; ++ } else { ++ txgain = ++ nphy_tpc_5GHz_txgain_rev5 ++ [txpi[core]]; ++ } ++ } else { ++ if (NREV_GE(phyrev, 5) && ++ (pi->srom_fem2g.extpagain == 3)) { ++ txgain = ++ nphy_tpc_txgain_HiPwrEPA ++ [txpi[core]]; ++ } else { ++ txgain = nphy_tpc_txgain_rev3 ++ [txpi[core]]; ++ } ++ } ++ } ++ } else { ++ txgain = nphy_tpc_txgain[txpi[core]]; ++ } ++ ++ if (NREV_GE(phyrev, 3)) ++ rad_gain = (txgain >> 16) & ((1 << (32 - 16 + 1)) - 1); ++ else ++ rad_gain = (txgain >> 16) & ((1 << (28 - 16 + 1)) - 1); ++ ++ if (NREV_GE(phyrev, 7)) ++ dac_gain = (txgain >> 8) & ((1 << (10 - 8 + 1)) - 1); ++ else ++ dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1); ++ ++ bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1); ++ ++ if (NREV_GE(phyrev, 3)) ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : ++ 0xa5), (0x1 << 8), (0x1 << 8)); ++ else ++ mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14)); ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? 0xaa : 0xab, dac_gain); ++ ++ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, ++ &rad_gain); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); ++ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); ++ m1m2 |= ((core == PHY_CORE_0) ? (bbmult << 8) : (bbmult << 0)); ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); ++ ++ if (PHY_IPA(pi)) { ++ wlc_phy_table_read_nphy(pi, ++ (core == ++ PHY_CORE_0 ? ++ NPHY_TBL_ID_CORE1TXPWRCTL : ++ NPHY_TBL_ID_CORE2TXPWRCTL), 1, ++ 576 + txpi[core], 32, ++ &rfpwr_offset); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1ff << 4), ++ ((s16) rfpwr_offset) << 4); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 2), (1) << 2); ++ ++ } ++ } ++ ++ and_phy_reg(pi, 0xbf, (u16) (~(0x1f << 0))); ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++static void ++wlc_phy_txpwr_nphy_srom_convert(u8 *srom_max, u16 *pwr_offset, ++ u8 tmp_max_pwr, u8 rate_start, ++ u8 rate_end) ++{ ++ u8 rate; ++ u8 word_num, nibble_num; ++ u8 tmp_nibble; ++ ++ for (rate = rate_start; rate <= rate_end; rate++) { ++ word_num = (rate - rate_start) >> 2; ++ nibble_num = (rate - rate_start) & 0x3; ++ tmp_nibble = (pwr_offset[word_num] >> 4 * nibble_num) & 0xf; ++ ++ srom_max[rate] = tmp_max_pwr - 2 * tmp_nibble; ++ } ++} ++ ++static void ++wlc_phy_txpwr_nphy_po_apply(u8 *srom_max, u8 pwr_offset, ++ u8 rate_start, u8 rate_end) ++{ ++ u8 rate; ++ ++ for (rate = rate_start; rate <= rate_end; rate++) ++ srom_max[rate] -= 2 * pwr_offset; ++} ++ ++void ++wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, ++ u8 rate_mcs_end, u8 rate_ofdm_start) ++{ ++ u8 rate1, rate2; ++ ++ rate2 = rate_ofdm_start; ++ for (rate1 = rate_mcs_start; rate1 <= rate_mcs_end - 1; rate1++) { ++ power[rate1] = power[rate2]; ++ rate2 += (rate1 == rate_mcs_start) ? 2 : 1; ++ } ++ power[rate_mcs_end] = power[rate_mcs_end - 1]; ++} ++ ++void ++wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, u8 rate_ofdm_start, ++ u8 rate_ofdm_end, u8 rate_mcs_start) ++{ ++ u8 rate1, rate2; ++ ++ for (rate1 = rate_ofdm_start, rate2 = rate_mcs_start; ++ rate1 <= rate_ofdm_end; rate1++, rate2++) { ++ power[rate1] = power[rate2]; ++ if (rate1 == rate_ofdm_start) ++ power[++rate1] = power[rate2]; ++ } ++} ++ ++void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi) ++{ ++ uint rate1, rate2, band_num; ++ u8 tmp_bw40po = 0, tmp_cddpo = 0, tmp_stbcpo = 0; ++ u8 tmp_max_pwr = 0; ++ u16 pwr_offsets1[2], *pwr_offsets2 = NULL; ++ u8 *tx_srom_max_rate = NULL; ++ ++ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); ++ band_num++) { ++ switch (band_num) { ++ case 0: ++ ++ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_2g, ++ pi->nphy_pwrctrl_info[1].max_pwr_2g); ++ ++ pwr_offsets1[0] = pi->cck2gpo; ++ wlc_phy_txpwr_nphy_srom_convert(pi->tx_srom_max_rate_2g, ++ pwr_offsets1, ++ tmp_max_pwr, ++ TXP_FIRST_CCK, ++ TXP_LAST_CCK); ++ ++ pwr_offsets1[0] = (u16) (pi->ofdm2gpo & 0xffff); ++ pwr_offsets1[1] = ++ (u16) (pi->ofdm2gpo >> 16) & 0xffff; ++ ++ pwr_offsets2 = pi->mcs2gpo; ++ ++ tmp_cddpo = pi->cdd2gpo; ++ tmp_stbcpo = pi->stbc2gpo; ++ tmp_bw40po = pi->bw402gpo; ++ ++ tx_srom_max_rate = pi->tx_srom_max_rate_2g; ++ break; ++ case 1: ++ ++ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gm, ++ pi->nphy_pwrctrl_info[1].max_pwr_5gm); ++ ++ pwr_offsets1[0] = (u16) (pi->ofdm5gpo & 0xffff); ++ pwr_offsets1[1] = ++ (u16) (pi->ofdm5gpo >> 16) & 0xffff; ++ ++ pwr_offsets2 = pi->mcs5gpo; ++ ++ tmp_cddpo = pi->cdd5gpo; ++ tmp_stbcpo = pi->stbc5gpo; ++ tmp_bw40po = pi->bw405gpo; ++ ++ tx_srom_max_rate = pi->tx_srom_max_rate_5g_mid; ++ break; ++ case 2: ++ ++ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gl, ++ pi->nphy_pwrctrl_info[1].max_pwr_5gl); ++ ++ pwr_offsets1[0] = (u16) (pi->ofdm5glpo & 0xffff); ++ pwr_offsets1[1] = ++ (u16) (pi->ofdm5glpo >> 16) & 0xffff; ++ ++ pwr_offsets2 = pi->mcs5glpo; ++ ++ tmp_cddpo = pi->cdd5glpo; ++ tmp_stbcpo = pi->stbc5glpo; ++ tmp_bw40po = pi->bw405glpo; ++ ++ tx_srom_max_rate = pi->tx_srom_max_rate_5g_low; ++ break; ++ case 3: ++ ++ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gh, ++ pi->nphy_pwrctrl_info[1].max_pwr_5gh); ++ ++ pwr_offsets1[0] = (u16) (pi->ofdm5ghpo & 0xffff); ++ pwr_offsets1[1] = ++ (u16) (pi->ofdm5ghpo >> 16) & 0xffff; ++ ++ pwr_offsets2 = pi->mcs5ghpo; ++ ++ tmp_cddpo = pi->cdd5ghpo; ++ tmp_stbcpo = pi->stbc5ghpo; ++ tmp_bw40po = pi->bw405ghpo; ++ ++ tx_srom_max_rate = pi->tx_srom_max_rate_5g_hi; ++ break; ++ } ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets1, ++ tmp_max_pwr, TXP_FIRST_OFDM, ++ TXP_LAST_OFDM); ++ ++ wlc_phy_ofdm_to_mcs_powers_nphy(tx_srom_max_rate, ++ TXP_FIRST_MCS_20_SISO, ++ TXP_LAST_MCS_20_SISO, ++ TXP_FIRST_OFDM); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2, ++ tmp_max_pwr, ++ TXP_FIRST_MCS_20_CDD, ++ TXP_LAST_MCS_20_CDD); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo, ++ TXP_FIRST_MCS_20_CDD, ++ TXP_LAST_MCS_20_CDD); ++ ++ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, ++ TXP_FIRST_OFDM_20_CDD, ++ TXP_LAST_OFDM_20_CDD, ++ TXP_FIRST_MCS_20_CDD); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2, ++ tmp_max_pwr, ++ TXP_FIRST_MCS_20_STBC, ++ TXP_LAST_MCS_20_STBC); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, ++ tmp_stbcpo, ++ TXP_FIRST_MCS_20_STBC, ++ TXP_LAST_MCS_20_STBC); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, ++ &pwr_offsets2[2], tmp_max_pwr, ++ TXP_FIRST_MCS_20_SDM, ++ TXP_LAST_MCS_20_SDM); ++ ++ if (NPHY_IS_SROM_REINTERPRET) { ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, ++ &pwr_offsets2[4], ++ tmp_max_pwr, ++ TXP_FIRST_MCS_40_SISO, ++ TXP_LAST_MCS_40_SISO); ++ ++ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, ++ TXP_FIRST_OFDM_40_SISO, ++ TXP_LAST_OFDM_40_SISO, ++ TXP_FIRST_MCS_40_SISO); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, ++ &pwr_offsets2[4], ++ tmp_max_pwr, ++ TXP_FIRST_MCS_40_CDD, ++ TXP_LAST_MCS_40_CDD); ++ ++ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo, ++ TXP_FIRST_MCS_40_CDD, ++ TXP_LAST_MCS_40_CDD); ++ ++ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, ++ TXP_FIRST_OFDM_40_CDD, ++ TXP_LAST_OFDM_40_CDD, ++ TXP_FIRST_MCS_40_CDD); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, ++ &pwr_offsets2[4], ++ tmp_max_pwr, ++ TXP_FIRST_MCS_40_STBC, ++ TXP_LAST_MCS_40_STBC); ++ ++ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, ++ tmp_stbcpo, ++ TXP_FIRST_MCS_40_STBC, ++ TXP_LAST_MCS_40_STBC); ++ ++ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, ++ &pwr_offsets2[6], ++ tmp_max_pwr, ++ TXP_FIRST_MCS_40_SDM, ++ TXP_LAST_MCS_40_SDM); ++ } else { ++ ++ for (rate1 = TXP_FIRST_OFDM_40_SISO, rate2 = ++ TXP_FIRST_OFDM; ++ rate1 <= TXP_LAST_MCS_40_SDM; ++ rate1++, rate2++) ++ tx_srom_max_rate[rate1] = ++ tx_srom_max_rate[rate2]; ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, ++ tmp_bw40po, ++ TXP_FIRST_OFDM_40_SISO, ++ TXP_LAST_MCS_40_SDM); ++ ++ tx_srom_max_rate[TXP_MCS_32] = ++ tx_srom_max_rate[TXP_FIRST_MCS_40_CDD]; ++ } ++ ++ return; ++} ++ ++void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi) ++{ ++ u8 tx_pwr_ctrl_state; ++ wlc_phy_txpwr_limit_to_tbl_nphy(pi); ++ wlc_phy_txpwrctrl_pwr_setup_nphy(pi); ++ ++ tx_pwr_ctrl_state = pi->nphy_txpwrctrl; ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); ++ (void)R_REG(&pi->regs->maccontrol); ++ udelay(1); ++ } ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); ++ ++ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) ++ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); ++} ++ ++static bool wlc_phy_txpwr_ison_nphy(struct brcms_phy *pi) ++{ ++ return read_phy_reg((pi), 0x1e7) & ((0x1 << 15) | ++ (0x1 << 14) | (0x1 << 13)); ++} ++ ++u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi) ++{ ++ u16 tmp; ++ u16 pwr_idx[2]; ++ ++ if (wlc_phy_txpwr_ison_nphy(pi)) { ++ pwr_idx[0] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_0); ++ pwr_idx[1] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_1); ++ ++ tmp = (pwr_idx[0] << 8) | pwr_idx[1]; ++ } else { ++ tmp = ((pi->nphy_txpwrindex[PHY_CORE_0].index_internal & 0xff) ++ << 8) | ++ (pi->nphy_txpwrindex[PHY_CORE_1].index_internal & 0xff); ++ } ++ ++ return tmp; ++} ++ ++void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi) ++{ ++ if (PHY_IPA(pi) ++ && (pi->nphy_force_papd_cal ++ || (wlc_phy_txpwr_ison_nphy(pi) ++ && ++ (((u32) ++ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 0) - ++ pi->nphy_papd_tx_gain_at_last_cal[0]) >= 4) ++ || ((u32) ++ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 1) - ++ pi->nphy_papd_tx_gain_at_last_cal[1]) >= 4))))) ++ wlc_phy_a4(pi, true); ++} ++ ++void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type) ++{ ++ u16 mask = 0, val = 0, ishw = 0; ++ u8 ctr; ++ uint core; ++ u32 tbl_offset; ++ u32 tbl_len; ++ u16 regval[84]; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ switch (ctrl_type) { ++ case PHY_TPC_HW_OFF: ++ case PHY_TPC_HW_ON: ++ pi->nphy_txpwrctrl = ctrl_type; ++ break; ++ default: ++ break; ++ } ++ ++ if (ctrl_type == PHY_TPC_HW_OFF) { ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ ++ if (wlc_phy_txpwr_ison_nphy(pi)) { ++ for (core = 0; core < pi->pubpi.phy_corenum; ++ core++) ++ pi->nphy_txpwr_idx[core] = ++ wlc_phy_txpwr_idx_cur_get_nphy( ++ pi, ++ (u8) core); ++ } ++ ++ } ++ ++ tbl_len = 84; ++ tbl_offset = 64; ++ for (ctr = 0; ctr < tbl_len; ctr++) ++ regval[ctr] = 0; ++ wlc_phy_table_write_nphy(pi, 26, tbl_len, tbl_offset, 16, ++ regval); ++ wlc_phy_table_write_nphy(pi, 27, tbl_len, tbl_offset, 16, ++ regval); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ and_phy_reg(pi, 0x1e7, ++ (u16) (~((0x1 << 15) | ++ (0x1 << 14) | (0x1 << 13)))); ++ else ++ and_phy_reg(pi, 0x1e7, ++ (u16) (~((0x1 << 14) | (0x1 << 13)))); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ or_phy_reg(pi, 0x8f, (0x1 << 8)); ++ or_phy_reg(pi, 0xa5, (0x1 << 8)); ++ } else { ++ or_phy_reg(pi, 0xa5, (0x1 << 14)); ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x53); ++ else if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x5a); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2) && ++ pi->bw == WL_CHANSPEC_BW_40) ++ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR, ++ MHF1_IQSWAP_WAR, BRCM_BAND_ALL); ++ ++ } else { ++ ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, ++ 8, pi->adj_pwr_tbl_nphy); ++ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, ++ 8, pi->adj_pwr_tbl_nphy); ++ ++ ishw = (ctrl_type == PHY_TPC_HW_ON) ? 0x1 : 0x0; ++ mask = (0x1 << 14) | (0x1 << 13); ++ val = (ishw << 14) | (ishw << 13); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ mask |= (0x1 << 15); ++ val |= (ishw << 15); ++ } ++ ++ mod_phy_reg(pi, 0x1e7, mask, val); ++ ++ if (CHSPEC_IS5G(pi->radio_chanspec)) { ++ if (NREV_GE(pi->pubpi.phy_rev, 7)) { ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x32); ++ mod_phy_reg(pi, 0x222, (0xff << 0), 0x32); ++ } else { ++ mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x64); ++ if (NREV_GT(pi->pubpi.phy_rev, 1)) ++ mod_phy_reg(pi, 0x222, ++ (0xff << 0), 0x64); ++ } ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ if ((pi->nphy_txpwr_idx[0] != 128) ++ && (pi->nphy_txpwr_idx[1] != 128)) ++ wlc_phy_txpwr_idx_cur_set_nphy(pi, ++ pi-> ++ nphy_txpwr_idx ++ [0], ++ pi-> ++ nphy_txpwr_idx ++ [1]); ++ } ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ and_phy_reg(pi, 0x8f, ~(0x1 << 8)); ++ and_phy_reg(pi, 0xa5, ~(0x1 << 8)); ++ } else { ++ and_phy_reg(pi, 0xa5, ~(0x1 << 14)); ++ } ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b); ++ else if (NREV_LT(pi->pubpi.phy_rev, 2)) ++ mod_phy_reg(pi, 0xdc, 0x00ff, 0x40); ++ ++ if (NREV_LT(pi->pubpi.phy_rev, 2) && ++ pi->bw == WL_CHANSPEC_BW_40) ++ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR, ++ 0x0, BRCM_BAND_ALL); ++ ++ if (PHY_IPA(pi)) { ++ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 2), (0) << 2); ++ ++ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 2), (0) << 2); ++ ++ } ++ ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++void ++wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex, ++ bool restore_cals) ++{ ++ u8 core, txpwrctl_tbl; ++ u16 tx_ind0, iq_ind0, lo_ind0; ++ u16 m1m2; ++ u32 txgain; ++ u16 rad_gain, dac_gain; ++ u8 bbmult; ++ u32 iqcomp; ++ u16 iqcomp_a, iqcomp_b; ++ u32 locomp; ++ u16 tmpval; ++ u8 tx_pwr_ctrl_state; ++ s32 rfpwr_offset; ++ u16 regval[2]; ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ ++ tx_ind0 = 192; ++ iq_ind0 = 320; ++ lo_ind0 = 448; ++ ++ for (core = 0; core < pi->pubpi.phy_corenum; core++) { ++ ++ if ((core_mask & (1 << core)) == 0) ++ continue; ++ ++ txpwrctl_tbl = (core == PHY_CORE_0) ? 26 : 27; ++ ++ if (txpwrindex < 0) { ++ if (pi->nphy_txpwrindex[core].index < 0) ++ continue; ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ mod_phy_reg(pi, 0x8f, ++ (0x1 << 8), ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride); ++ mod_phy_reg(pi, 0xa5, (0x1 << 8), ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride); ++ } else { ++ mod_phy_reg(pi, 0xa5, ++ (0x1 << 14), ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride); ++ } ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xaa : 0xab, ++ pi->nphy_txpwrindex[core].AfeCtrlDacGain); ++ ++ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, ++ &pi->nphy_txpwrindex[core]. ++ rad_gain); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); ++ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); ++ m1m2 |= ((core == PHY_CORE_0) ? ++ (pi->nphy_txpwrindex[core].bbmult << 8) : ++ (pi->nphy_txpwrindex[core].bbmult << 0)); ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); ++ ++ if (restore_cals) { ++ wlc_phy_table_write_nphy( ++ pi, 15, 2, (80 + 2 * core), 16, ++ &pi->nphy_txpwrindex[core].iqcomp_a); ++ wlc_phy_table_write_nphy( ++ pi, 15, 1, (85 + core), 16, ++ &pi->nphy_txpwrindex[core].locomp); ++ wlc_phy_table_write_nphy( ++ pi, 15, 1, (93 + core), 16, ++ &pi->nphy_txpwrindex[core].locomp); ++ } ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); ++ ++ pi->nphy_txpwrindex[core].index_internal = ++ pi->nphy_txpwrindex[core].index_internal_save; ++ } else { ++ ++ if (pi->nphy_txpwrindex[core].index < 0) { ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) { ++ mod_phy_reg(pi, 0x8f, ++ (0x1 << 8), ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride); ++ mod_phy_reg(pi, 0xa5, (0x1 << 8), ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride); ++ } else { ++ pi->nphy_txpwrindex[core]. ++ AfectrlOverride = ++ read_phy_reg(pi, 0xa5); ++ } ++ ++ pi->nphy_txpwrindex[core].AfeCtrlDacGain = ++ read_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xaa : 0xab); ++ ++ wlc_phy_table_read_nphy(pi, 7, 1, ++ (0x110 + core), 16, ++ &pi-> ++ nphy_txpwrindex[core]. ++ rad_gain); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, ++ &tmpval); ++ tmpval >>= ((core == PHY_CORE_0) ? 8 : 0); ++ tmpval &= 0xff; ++ pi->nphy_txpwrindex[core].bbmult = (u8) tmpval; ++ ++ wlc_phy_table_read_nphy(pi, 15, 2, ++ (80 + 2 * core), 16, ++ &pi-> ++ nphy_txpwrindex[core]. ++ iqcomp_a); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, (85 + core), ++ 16, ++ &pi-> ++ nphy_txpwrindex[core]. ++ locomp); ++ ++ pi->nphy_txpwrindex[core].index_internal_save = ++ pi->nphy_txpwrindex[core]. ++ index_internal; ++ } ++ ++ tx_pwr_ctrl_state = pi->nphy_txpwrctrl; ++ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 1)) ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); ++ ++ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, ++ (tx_ind0 + txpwrindex), 32, ++ &txgain); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ rad_gain = (txgain >> 16) & ++ ((1 << (32 - 16 + 1)) - 1); ++ else ++ rad_gain = (txgain >> 16) & ++ ((1 << (28 - 16 + 1)) - 1); ++ ++ dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1); ++ bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1); ++ ++ if (NREV_GE(pi->pubpi.phy_rev, 3)) ++ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : ++ 0xa5), (0x1 << 8), (0x1 << 8)); ++ else ++ mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14)); ++ ++ write_phy_reg(pi, (core == PHY_CORE_0) ? ++ 0xaa : 0xab, dac_gain); ++ ++ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, ++ &rad_gain); ++ ++ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); ++ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); ++ m1m2 |= ((core == PHY_CORE_0) ? ++ (bbmult << 8) : (bbmult << 0)); ++ ++ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); ++ ++ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, ++ (iq_ind0 + txpwrindex), 32, ++ &iqcomp); ++ iqcomp_a = (iqcomp >> 10) & ((1 << (19 - 10 + 1)) - 1); ++ iqcomp_b = (iqcomp >> 0) & ((1 << (9 - 0 + 1)) - 1); ++ ++ if (restore_cals) { ++ regval[0] = (u16) iqcomp_a; ++ regval[1] = (u16) iqcomp_b; ++ wlc_phy_table_write_nphy(pi, 15, 2, ++ (80 + 2 * core), 16, ++ regval); ++ } ++ ++ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, ++ (lo_ind0 + txpwrindex), 32, ++ &locomp); ++ if (restore_cals) ++ wlc_phy_table_write_nphy(pi, 15, 1, (85 + core), ++ 16, &locomp); ++ ++ if (NREV_IS(pi->pubpi.phy_rev, 1)) ++ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); ++ ++ if (PHY_IPA(pi)) { ++ wlc_phy_table_read_nphy(pi, ++ (core == PHY_CORE_0 ? ++ NPHY_TBL_ID_CORE1TXPWRCTL : ++ NPHY_TBL_ID_CORE2TXPWRCTL), ++ 1, 576 + txpwrindex, 32, ++ &rfpwr_offset); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1ff << 4), ++ ((s16) rfpwr_offset) << 4); ++ ++ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : ++ 0x29b, (0x1 << 2), (1) << 2); ++ ++ } ++ ++ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); ++ } ++ ++ pi->nphy_txpwrindex[core].index = txpwrindex; ++ } ++ ++ if (pi->phyhang_avoid) ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++} ++ ++void ++wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, u8 *max_pwr, ++ u8 txp_rate_idx) ++{ ++ u8 chan_freq_range; ++ ++ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, chan); ++ switch (chan_freq_range) { ++ case WL_CHAN_FREQ_RANGE_2G: ++ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GM: ++ *max_pwr = pi->tx_srom_max_rate_5g_mid[txp_rate_idx]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GL: ++ *max_pwr = pi->tx_srom_max_rate_5g_low[txp_rate_idx]; ++ break; ++ case WL_CHAN_FREQ_RANGE_5GH: ++ *max_pwr = pi->tx_srom_max_rate_5g_hi[txp_rate_idx]; ++ break; ++ default: ++ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; ++ break; ++ } ++ ++ return; ++} ++ ++void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable) ++{ ++ u16 clip_off[] = { 0xffff, 0xffff }; ++ ++ if (enable) { ++ if (pi->nphy_deaf_count == 0) { ++ pi->classifier_state = ++ wlc_phy_classifier_nphy(pi, 0, 0); ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); ++ wlc_phy_clip_det_nphy(pi, 0, pi->clip_state); ++ wlc_phy_clip_det_nphy(pi, 1, clip_off); ++ } ++ ++ pi->nphy_deaf_count++; ++ ++ wlc_phy_resetcca_nphy(pi); ++ ++ } else { ++ pi->nphy_deaf_count--; ++ ++ if (pi->nphy_deaf_count == 0) { ++ wlc_phy_classifier_nphy(pi, (0x7 << 0), ++ pi->classifier_state); ++ wlc_phy_clip_det_nphy(pi, 1, pi->clip_state); ++ } ++ } ++} ++ ++void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode) ++{ ++ wlapi_suspend_mac_and_wait(pi->sh->physhim); ++ ++ if (mode) { ++ if (pi->nphy_deaf_count == 0) ++ wlc_phy_stay_in_carriersearch_nphy(pi, true); ++ } else if (pi->nphy_deaf_count > 0) { ++ wlc_phy_stay_in_carriersearch_nphy(pi, false); ++ } ++ ++ wlapi_enable_mac(pi->sh->physhim); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c.orig 2011-11-09 13:46:58.276800245 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c 2011-11-09 13:47:17.032565765 -0500 +@@ -0,0 +1,308 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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 "phy_qmath.h" ++ ++/* ++ * Description: This function make 16 bit unsigned multiplication. ++ * To fit the output into 16 bits the 32 bit multiplication result is right ++ * shifted by 16 bits. ++ */ ++u16 qm_mulu16(u16 op1, u16 op2) ++{ ++ return (u16) (((u32) op1 * (u32) op2) >> 16); ++} ++ ++/* ++ * Description: This function make 16 bit multiplication and return the result ++ * in 16 bits. To fit the multiplication result into 16 bits the multiplication ++ * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits ++ * is done to remove the extra sign bit formed due to the multiplication. ++ * When both the 16bit inputs are 0x8000 then the output is saturated to ++ * 0x7fffffff. ++ */ ++s16 qm_muls16(s16 op1, s16 op2) ++{ ++ s32 result; ++ if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000) ++ result = 0x7fffffff; ++ else ++ result = ((s32) (op1) * (s32) (op2)); ++ ++ return (s16) (result >> 15); ++} ++ ++/* ++ * Description: This function add two 32 bit numbers and return the 32bit ++ * result. If the result overflow 32 bits, the output will be saturated to ++ * 32bits. ++ */ ++s32 qm_add32(s32 op1, s32 op2) ++{ ++ s32 result; ++ result = op1 + op2; ++ if (op1 < 0 && op2 < 0 && result > 0) ++ result = 0x80000000; ++ else if (op1 > 0 && op2 > 0 && result < 0) ++ result = 0x7fffffff; ++ ++ return result; ++} ++ ++/* ++ * Description: This function add two 16 bit numbers and return the 16bit ++ * result. If the result overflow 16 bits, the output will be saturated to ++ * 16bits. ++ */ ++s16 qm_add16(s16 op1, s16 op2) ++{ ++ s16 result; ++ s32 temp = (s32) op1 + (s32) op2; ++ if (temp > (s32) 0x7fff) ++ result = (s16) 0x7fff; ++ else if (temp < (s32) 0xffff8000) ++ result = (s16) 0xffff8000; ++ else ++ result = (s16) temp; ++ ++ return result; ++} ++ ++/* ++ * Description: This function make 16 bit subtraction and return the 16bit ++ * result. If the result overflow 16 bits, the output will be saturated to ++ * 16bits. ++ */ ++s16 qm_sub16(s16 op1, s16 op2) ++{ ++ s16 result; ++ s32 temp = (s32) op1 - (s32) op2; ++ if (temp > (s32) 0x7fff) ++ result = (s16) 0x7fff; ++ else if (temp < (s32) 0xffff8000) ++ result = (s16) 0xffff8000; ++ else ++ result = (s16) temp; ++ ++ return result; ++} ++ ++/* ++ * Description: This function make a 32 bit saturated left shift when the ++ * specified shift is +ve. This function will make a 32 bit right shift when ++ * the specified shift is -ve. This function return the result after shifting ++ * operation. ++ */ ++s32 qm_shl32(s32 op, int shift) ++{ ++ int i; ++ s32 result; ++ result = op; ++ if (shift > 31) ++ shift = 31; ++ else if (shift < -31) ++ shift = -31; ++ if (shift >= 0) { ++ for (i = 0; i < shift; i++) ++ result = qm_add32(result, result); ++ } else { ++ result = result >> (-shift); ++ } ++ ++ return result; ++} ++ ++/* ++ * Description: This function make a 16 bit saturated left shift when the ++ * specified shift is +ve. This function will make a 16 bit right shift when ++ * the specified shift is -ve. This function return the result after shifting ++ * operation. ++ */ ++s16 qm_shl16(s16 op, int shift) ++{ ++ int i; ++ s16 result; ++ result = op; ++ if (shift > 15) ++ shift = 15; ++ else if (shift < -15) ++ shift = -15; ++ if (shift > 0) { ++ for (i = 0; i < shift; i++) ++ result = qm_add16(result, result); ++ } else { ++ result = result >> (-shift); ++ } ++ ++ return result; ++} ++ ++/* ++ * Description: This function make a 16 bit right shift when shift is +ve. ++ * This function make a 16 bit saturated left shift when shift is -ve. This ++ * function return the result of the shift operation. ++ */ ++s16 qm_shr16(s16 op, int shift) ++{ ++ return qm_shl16(op, -shift); ++} ++ ++/* ++ * Description: This function return the number of redundant sign bits in a ++ * 32 bit number. Example: qm_norm32(0x00000080) = 23 ++ */ ++s16 qm_norm32(s32 op) ++{ ++ u16 u16extraSignBits; ++ if (op == 0) { ++ return 31; ++ } else { ++ u16extraSignBits = 0; ++ while ((op >> 31) == (op >> 30)) { ++ u16extraSignBits++; ++ op = op << 1; ++ } ++ } ++ return u16extraSignBits; ++} ++ ++/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */ ++static const s16 log_table[] = { ++ 0, ++ 1455, ++ 2866, ++ 4236, ++ 5568, ++ 6863, ++ 8124, ++ 9352, ++ 10549, ++ 11716, ++ 12855, ++ 13968, ++ 15055, ++ 16117, ++ 17156, ++ 18173, ++ 19168, ++ 20143, ++ 21098, ++ 22034, ++ 22952, ++ 23852, ++ 24736, ++ 25604, ++ 26455, ++ 27292, ++ 28114, ++ 28922, ++ 29717, ++ 30498, ++ 31267, ++ 32024 ++}; ++ ++#define LOG_TABLE_SIZE 32 /* log_table size */ ++#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */ ++#define Q_LOG_TABLE 15 /* qformat of log_table */ ++#define LOG10_2 19728 /* log10(2) in q.16 */ ++ ++/* ++ * Description: ++ * This routine takes the input number N and its q format qN and compute ++ * the log10(N). This routine first normalizes the input no N. Then N is in ++ * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1). ++ * Then log2(mag * 2^x) = log2(mag) + x is computed. From that ++ * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed. ++ * This routine looks the log2 value in the table considering ++ * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next ++ * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used ++ * for interpolation. ++ * Inputs: ++ * N - number to which log10 has to be found. ++ * qN - q format of N ++ * log10N - address where log10(N) will be written. ++ * qLog10N - address where log10N qformat will be written. ++ * Note/Problem: ++ * For accurate results input should be in normalized or near normalized form. ++ */ ++void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N) ++{ ++ s16 s16norm, s16tableIndex, s16errorApproximation; ++ u16 u16offset; ++ s32 s32log; ++ ++ /* normalize the N. */ ++ s16norm = qm_norm32(N); ++ N = N << s16norm; ++ ++ /* The qformat of N after normalization. ++ * -30 is added to treat the no as between 1.0 to 2.0 ++ * i.e. after adding the -30 to the qformat the decimal point will be ++ * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e. ++ * at the right side of 30th bit. ++ */ ++ qN = qN + s16norm - 30; ++ ++ /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the ++ * MSB */ ++ s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE))); ++ ++ /* remove the MSB. the MSB is always 1 after normalization. */ ++ s16tableIndex = ++ s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1); ++ ++ /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */ ++ N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1); ++ ++ /* take the offset as the 16 MSBS after table index. ++ */ ++ u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16))); ++ ++ /* look the log value in the table. */ ++ s32log = log_table[s16tableIndex]; /* q.15 format */ ++ ++ /* interpolate using the offset. q.15 format. */ ++ s16errorApproximation = (s16) qm_mulu16(u16offset, ++ (u16) (log_table[s16tableIndex + 1] - ++ log_table[s16tableIndex])); ++ ++ /* q.15 format */ ++ s32log = qm_add16((s16) s32log, s16errorApproximation); ++ ++ /* adjust for the qformat of the N as ++ * log2(mag * 2^x) = log2(mag) + x ++ */ ++ s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */ ++ ++ /* normalize the result. */ ++ s16norm = qm_norm32(s32log); ++ ++ /* bring all the important bits into lower 16 bits */ ++ /* q.15+s16norm-16 format */ ++ s32log = qm_shl32(s32log, s16norm - 16); ++ ++ /* compute the log10(N) by multiplying log2(N) with log10(2). ++ * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2) ++ * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16) ++ */ ++ *log10N = qm_muls16((s16) s32log, (s16) LOG10_2); ++ ++ /* write the q format of the result. */ ++ *qLog10N = 15 + s16norm - 16 + 1; ++ ++ return; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h.orig 2011-11-09 13:46:58.276800245 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h 2011-11-09 13:47:17.032565765 -0500 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_QMATH_H_ ++#define _BRCM_QMATH_H_ ++ ++#include ++ ++u16 qm_mulu16(u16 op1, u16 op2); ++ ++s16 qm_muls16(s16 op1, s16 op2); ++ ++s32 qm_add32(s32 op1, s32 op2); ++ ++s16 qm_add16(s16 op1, s16 op2); ++ ++s16 qm_sub16(s16 op1, s16 op2); ++ ++s32 qm_shl32(s32 op, int shift); ++ ++s16 qm_shl16(s16 op, int shift); ++ ++s16 qm_shr16(s16 op, int shift); ++ ++s16 qm_norm32(s32 op); ++ ++void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N); ++ ++#endif /* #ifndef _BRCM_QMATH_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h.orig 2011-11-09 13:46:58.277800233 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h 2011-11-09 13:47:17.035565729 -0500 +@@ -0,0 +1,1533 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_PHY_RADIO_H_ ++#define _BRCM_PHY_RADIO_H_ ++ ++#define RADIO_IDCODE 0x01 ++ ++#define RADIO_DEFAULT_CORE 0 ++ ++#define RXC0_RSSI_RST 0x80 ++#define RXC0_MODE_RSSI 0x40 ++#define RXC0_MODE_OFF 0x20 ++#define RXC0_MODE_CM 0x10 ++#define RXC0_LAN_LOAD 0x08 ++#define RXC0_OFF_ADJ_MASK 0x07 ++ ++#define TXC0_MODE_TXLPF 0x04 ++#define TXC0_PA_TSSI_EN 0x02 ++#define TXC0_TSSI_EN 0x01 ++ ++#define TXC1_PA_GAIN_MASK 0x60 ++#define TXC1_PA_GAIN_3DB 0x40 ++#define TXC1_PA_GAIN_2DB 0x20 ++#define TXC1_TX_MIX_GAIN 0x10 ++#define TXC1_OFF_I_MASK 0x0c ++#define TXC1_OFF_Q_MASK 0x03 ++ ++#define RADIO_2055_READ_OFF 0x100 ++#define RADIO_2057_READ_OFF 0x200 ++ ++#define RADIO_2055_GEN_SPARE 0x00 ++#define RADIO_2055_SP_PIN_PD 0x02 ++#define RADIO_2055_SP_RSSI_CORE1 0x03 ++#define RADIO_2055_SP_PD_MISC_CORE1 0x04 ++#define RADIO_2055_SP_RSSI_CORE2 0x05 ++#define RADIO_2055_SP_PD_MISC_CORE2 0x06 ++#define RADIO_2055_SP_RX_GC1_CORE1 0x07 ++#define RADIO_2055_SP_RX_GC2_CORE1 0x08 ++#define RADIO_2055_SP_RX_GC1_CORE2 0x09 ++#define RADIO_2055_SP_RX_GC2_CORE2 0x0a ++#define RADIO_2055_SP_LPF_BW_SELECT_CORE1 0x0b ++#define RADIO_2055_SP_LPF_BW_SELECT_CORE2 0x0c ++#define RADIO_2055_SP_TX_GC1_CORE1 0x0d ++#define RADIO_2055_SP_TX_GC2_CORE1 0x0e ++#define RADIO_2055_SP_TX_GC1_CORE2 0x0f ++#define RADIO_2055_SP_TX_GC2_CORE2 0x10 ++#define RADIO_2055_MASTER_CNTRL1 0x11 ++#define RADIO_2055_MASTER_CNTRL2 0x12 ++#define RADIO_2055_PD_LGEN 0x13 ++#define RADIO_2055_PD_PLL_TS 0x14 ++#define RADIO_2055_PD_CORE1_LGBUF 0x15 ++#define RADIO_2055_PD_CORE1_TX 0x16 ++#define RADIO_2055_PD_CORE1_RXTX 0x17 ++#define RADIO_2055_PD_CORE1_RSSI_MISC 0x18 ++#define RADIO_2055_PD_CORE2_LGBUF 0x19 ++#define RADIO_2055_PD_CORE2_TX 0x1a ++#define RADIO_2055_PD_CORE2_RXTX 0x1b ++#define RADIO_2055_PD_CORE2_RSSI_MISC 0x1c ++#define RADIO_2055_PWRDET_LGEN 0x1d ++#define RADIO_2055_PWRDET_LGBUF_CORE1 0x1e ++#define RADIO_2055_PWRDET_RXTX_CORE1 0x1f ++#define RADIO_2055_PWRDET_LGBUF_CORE2 0x20 ++#define RADIO_2055_PWRDET_RXTX_CORE2 0x21 ++#define RADIO_2055_RRCCAL_CNTRL_SPARE 0x22 ++#define RADIO_2055_RRCCAL_N_OPT_SEL 0x23 ++#define RADIO_2055_CAL_MISC 0x24 ++#define RADIO_2055_CAL_COUNTER_OUT 0x25 ++#define RADIO_2055_CAL_COUNTER_OUT2 0x26 ++#define RADIO_2055_CAL_CVAR_CNTRL 0x27 ++#define RADIO_2055_CAL_RVAR_CNTRL 0x28 ++#define RADIO_2055_CAL_LPO_CNTRL 0x29 ++#define RADIO_2055_CAL_TS 0x2a ++#define RADIO_2055_CAL_RCCAL_READ_TS 0x2b ++#define RADIO_2055_CAL_RCAL_READ_TS 0x2c ++#define RADIO_2055_PAD_DRIVER 0x2d ++#define RADIO_2055_XO_CNTRL1 0x2e ++#define RADIO_2055_XO_CNTRL2 0x2f ++#define RADIO_2055_XO_REGULATOR 0x30 ++#define RADIO_2055_XO_MISC 0x31 ++#define RADIO_2055_PLL_LF_C1 0x32 ++#define RADIO_2055_PLL_CAL_VTH 0x33 ++#define RADIO_2055_PLL_LF_C2 0x34 ++#define RADIO_2055_PLL_REF 0x35 ++#define RADIO_2055_PLL_LF_R1 0x36 ++#define RADIO_2055_PLL_PFD_CP 0x37 ++#define RADIO_2055_PLL_IDAC_CPOPAMP 0x38 ++#define RADIO_2055_PLL_CP_REGULATOR 0x39 ++#define RADIO_2055_PLL_RCAL 0x3a ++#define RADIO_2055_RF_PLL_MOD0 0x3b ++#define RADIO_2055_RF_PLL_MOD1 0x3c ++#define RADIO_2055_RF_MMD_IDAC1 0x3d ++#define RADIO_2055_RF_MMD_IDAC0 0x3e ++#define RADIO_2055_RF_MMD_SPARE 0x3f ++#define RADIO_2055_VCO_CAL1 0x40 ++#define RADIO_2055_VCO_CAL2 0x41 ++#define RADIO_2055_VCO_CAL3 0x42 ++#define RADIO_2055_VCO_CAL4 0x43 ++#define RADIO_2055_VCO_CAL5 0x44 ++#define RADIO_2055_VCO_CAL6 0x45 ++#define RADIO_2055_VCO_CAL7 0x46 ++#define RADIO_2055_VCO_CAL8 0x47 ++#define RADIO_2055_VCO_CAL9 0x48 ++#define RADIO_2055_VCO_CAL10 0x49 ++#define RADIO_2055_VCO_CAL11 0x4a ++#define RADIO_2055_VCO_CAL12 0x4b ++#define RADIO_2055_VCO_CAL13 0x4c ++#define RADIO_2055_VCO_CAL14 0x4d ++#define RADIO_2055_VCO_CAL15 0x4e ++#define RADIO_2055_VCO_CAL16 0x4f ++#define RADIO_2055_VCO_KVCO 0x50 ++#define RADIO_2055_VCO_CAP_TAIL 0x51 ++#define RADIO_2055_VCO_IDAC_VCO 0x52 ++#define RADIO_2055_VCO_REGULATOR 0x53 ++#define RADIO_2055_PLL_RF_VTH 0x54 ++#define RADIO_2055_LGBUF_CEN_BUF 0x55 ++#define RADIO_2055_LGEN_TUNE1 0x56 ++#define RADIO_2055_LGEN_TUNE2 0x57 ++#define RADIO_2055_LGEN_IDAC1 0x58 ++#define RADIO_2055_LGEN_IDAC2 0x59 ++#define RADIO_2055_LGEN_BIAS_CNT 0x5a ++#define RADIO_2055_LGEN_BIAS_IDAC 0x5b ++#define RADIO_2055_LGEN_RCAL 0x5c ++#define RADIO_2055_LGEN_DIV 0x5d ++#define RADIO_2055_LGEN_SPARE2 0x5e ++#define RADIO_2055_CORE1_LGBUF_A_TUNE 0x5f ++#define RADIO_2055_CORE1_LGBUF_G_TUNE 0x60 ++#define RADIO_2055_CORE1_LGBUF_DIV 0x61 ++#define RADIO_2055_CORE1_LGBUF_A_IDAC 0x62 ++#define RADIO_2055_CORE1_LGBUF_G_IDAC 0x63 ++#define RADIO_2055_CORE1_LGBUF_IDACFIL_OVR 0x64 ++#define RADIO_2055_CORE1_LGBUF_SPARE 0x65 ++#define RADIO_2055_CORE1_RXRF_SPC1 0x66 ++#define RADIO_2055_CORE1_RXRF_REG1 0x67 ++#define RADIO_2055_CORE1_RXRF_REG2 0x68 ++#define RADIO_2055_CORE1_RXRF_RCAL 0x69 ++#define RADIO_2055_CORE1_RXBB_BUFI_LPFCMP 0x6a ++#define RADIO_2055_CORE1_RXBB_LPF 0x6b ++#define RADIO_2055_CORE1_RXBB_MIDAC_HIPAS 0x6c ++#define RADIO_2055_CORE1_RXBB_VGA1_IDAC 0x6d ++#define RADIO_2055_CORE1_RXBB_VGA2_IDAC 0x6e ++#define RADIO_2055_CORE1_RXBB_VGA3_IDAC 0x6f ++#define RADIO_2055_CORE1_RXBB_BUFO_CTRL 0x70 ++#define RADIO_2055_CORE1_RXBB_RCCAL_CTRL 0x71 ++#define RADIO_2055_CORE1_RXBB_RSSI_CTRL1 0x72 ++#define RADIO_2055_CORE1_RXBB_RSSI_CTRL2 0x73 ++#define RADIO_2055_CORE1_RXBB_RSSI_CTRL3 0x74 ++#define RADIO_2055_CORE1_RXBB_RSSI_CTRL4 0x75 ++#define RADIO_2055_CORE1_RXBB_RSSI_CTRL5 0x76 ++#define RADIO_2055_CORE1_RXBB_REGULATOR 0x77 ++#define RADIO_2055_CORE1_RXBB_SPARE1 0x78 ++#define RADIO_2055_CORE1_RXTXBB_RCAL 0x79 ++#define RADIO_2055_CORE1_TXRF_SGM_PGA 0x7a ++#define RADIO_2055_CORE1_TXRF_SGM_PAD 0x7b ++#define RADIO_2055_CORE1_TXRF_CNTR_PGA1 0x7c ++#define RADIO_2055_CORE1_TXRF_CNTR_PAD1 0x7d ++#define RADIO_2055_CORE1_TX_RFPGA_IDAC 0x7e ++#define RADIO_2055_CORE1_TX_PGA_PAD_TN 0x7f ++#define RADIO_2055_CORE1_TX_PAD_IDAC1 0x80 ++#define RADIO_2055_CORE1_TX_PAD_IDAC2 0x81 ++#define RADIO_2055_CORE1_TX_MX_BGTRIM 0x82 ++#define RADIO_2055_CORE1_TXRF_RCAL 0x83 ++#define RADIO_2055_CORE1_TXRF_PAD_TSSI1 0x84 ++#define RADIO_2055_CORE1_TXRF_PAD_TSSI2 0x85 ++#define RADIO_2055_CORE1_TX_RF_SPARE 0x86 ++#define RADIO_2055_CORE1_TXRF_IQCAL1 0x87 ++#define RADIO_2055_CORE1_TXRF_IQCAL2 0x88 ++#define RADIO_2055_CORE1_TXBB_RCCAL_CTRL 0x89 ++#define RADIO_2055_CORE1_TXBB_LPF1 0x8a ++#define RADIO_2055_CORE1_TX_VOS_CNCL 0x8b ++#define RADIO_2055_CORE1_TX_LPF_MXGM_IDAC 0x8c ++#define RADIO_2055_CORE1_TX_BB_MXGM 0x8d ++#define RADIO_2055_CORE2_LGBUF_A_TUNE 0x8e ++#define RADIO_2055_CORE2_LGBUF_G_TUNE 0x8f ++#define RADIO_2055_CORE2_LGBUF_DIV 0x90 ++#define RADIO_2055_CORE2_LGBUF_A_IDAC 0x91 ++#define RADIO_2055_CORE2_LGBUF_G_IDAC 0x92 ++#define RADIO_2055_CORE2_LGBUF_IDACFIL_OVR 0x93 ++#define RADIO_2055_CORE2_LGBUF_SPARE 0x94 ++#define RADIO_2055_CORE2_RXRF_SPC1 0x95 ++#define RADIO_2055_CORE2_RXRF_REG1 0x96 ++#define RADIO_2055_CORE2_RXRF_REG2 0x97 ++#define RADIO_2055_CORE2_RXRF_RCAL 0x98 ++#define RADIO_2055_CORE2_RXBB_BUFI_LPFCMP 0x99 ++#define RADIO_2055_CORE2_RXBB_LPF 0x9a ++#define RADIO_2055_CORE2_RXBB_MIDAC_HIPAS 0x9b ++#define RADIO_2055_CORE2_RXBB_VGA1_IDAC 0x9c ++#define RADIO_2055_CORE2_RXBB_VGA2_IDAC 0x9d ++#define RADIO_2055_CORE2_RXBB_VGA3_IDAC 0x9e ++#define RADIO_2055_CORE2_RXBB_BUFO_CTRL 0x9f ++#define RADIO_2055_CORE2_RXBB_RCCAL_CTRL 0xa0 ++#define RADIO_2055_CORE2_RXBB_RSSI_CTRL1 0xa1 ++#define RADIO_2055_CORE2_RXBB_RSSI_CTRL2 0xa2 ++#define RADIO_2055_CORE2_RXBB_RSSI_CTRL3 0xa3 ++#define RADIO_2055_CORE2_RXBB_RSSI_CTRL4 0xa4 ++#define RADIO_2055_CORE2_RXBB_RSSI_CTRL5 0xa5 ++#define RADIO_2055_CORE2_RXBB_REGULATOR 0xa6 ++#define RADIO_2055_CORE2_RXBB_SPARE1 0xa7 ++#define RADIO_2055_CORE2_RXTXBB_RCAL 0xa8 ++#define RADIO_2055_CORE2_TXRF_SGM_PGA 0xa9 ++#define RADIO_2055_CORE2_TXRF_SGM_PAD 0xaa ++#define RADIO_2055_CORE2_TXRF_CNTR_PGA1 0xab ++#define RADIO_2055_CORE2_TXRF_CNTR_PAD1 0xac ++#define RADIO_2055_CORE2_TX_RFPGA_IDAC 0xad ++#define RADIO_2055_CORE2_TX_PGA_PAD_TN 0xae ++#define RADIO_2055_CORE2_TX_PAD_IDAC1 0xaf ++#define RADIO_2055_CORE2_TX_PAD_IDAC2 0xb0 ++#define RADIO_2055_CORE2_TX_MX_BGTRIM 0xb1 ++#define RADIO_2055_CORE2_TXRF_RCAL 0xb2 ++#define RADIO_2055_CORE2_TXRF_PAD_TSSI1 0xb3 ++#define RADIO_2055_CORE2_TXRF_PAD_TSSI2 0xb4 ++#define RADIO_2055_CORE2_TX_RF_SPARE 0xb5 ++#define RADIO_2055_CORE2_TXRF_IQCAL1 0xb6 ++#define RADIO_2055_CORE2_TXRF_IQCAL2 0xb7 ++#define RADIO_2055_CORE2_TXBB_RCCAL_CTRL 0xb8 ++#define RADIO_2055_CORE2_TXBB_LPF1 0xb9 ++#define RADIO_2055_CORE2_TX_VOS_CNCL 0xba ++#define RADIO_2055_CORE2_TX_LPF_MXGM_IDAC 0xbb ++#define RADIO_2055_CORE2_TX_BB_MXGM 0xbc ++#define RADIO_2055_PRG_GC_HPVGA23_21 0xbd ++#define RADIO_2055_PRG_GC_HPVGA23_22 0xbe ++#define RADIO_2055_PRG_GC_HPVGA23_23 0xbf ++#define RADIO_2055_PRG_GC_HPVGA23_24 0xc0 ++#define RADIO_2055_PRG_GC_HPVGA23_25 0xc1 ++#define RADIO_2055_PRG_GC_HPVGA23_26 0xc2 ++#define RADIO_2055_PRG_GC_HPVGA23_27 0xc3 ++#define RADIO_2055_PRG_GC_HPVGA23_28 0xc4 ++#define RADIO_2055_PRG_GC_HPVGA23_29 0xc5 ++#define RADIO_2055_PRG_GC_HPVGA23_30 0xc6 ++#define RADIO_2055_CORE1_LNA_GAINBST 0xcd ++#define RADIO_2055_CORE1_B0_NBRSSI_VCM 0xd2 ++#define RADIO_2055_CORE1_GEN_SPARE2 0xd6 ++#define RADIO_2055_CORE2_LNA_GAINBST 0xd9 ++#define RADIO_2055_CORE2_B0_NBRSSI_VCM 0xde ++#define RADIO_2055_CORE2_GEN_SPARE2 0xe2 ++ ++#define RADIO_2055_GAINBST_GAIN_DB 6 ++#define RADIO_2055_GAINBST_CODE 0x6 ++ ++#define RADIO_2055_JTAGCTRL_MASK 0x04 ++#define RADIO_2055_JTAGSYNC_MASK 0x08 ++#define RADIO_2055_RRCAL_START 0x40 ++#define RADIO_2055_RRCAL_RST_N 0x01 ++#define RADIO_2055_CAL_LPO_ENABLE 0x80 ++#define RADIO_2055_RCAL_DONE 0x80 ++#define RADIO_2055_NBRSSI_VCM_I_MASK 0x03 ++#define RADIO_2055_NBRSSI_VCM_I_SHIFT 0x00 ++#define RADIO_2055_NBRSSI_VCM_Q_MASK 0x03 ++#define RADIO_2055_NBRSSI_VCM_Q_SHIFT 0x00 ++#define RADIO_2055_WBRSSI_VCM_IQ_MASK 0x0c ++#define RADIO_2055_WBRSSI_VCM_IQ_SHIFT 0x02 ++#define RADIO_2055_NBRSSI_PD 0x01 ++#define RADIO_2055_WBRSSI_G1_PD 0x04 ++#define RADIO_2055_WBRSSI_G2_PD 0x02 ++#define RADIO_2055_NBRSSI_SEL 0x01 ++#define RADIO_2055_WBRSSI_G1_SEL 0x04 ++#define RADIO_2055_WBRSSI_G2_SEL 0x02 ++#define RADIO_2055_COUPLE_RX_MASK 0x01 ++#define RADIO_2055_COUPLE_TX_MASK 0x02 ++#define RADIO_2055_GAINBST_DISABLE 0x02 ++#define RADIO_2055_GAINBST_VAL_MASK 0x07 ++#define RADIO_2055_RXMX_GC_MASK 0x0c ++ ++#define RADIO_MIMO_CORESEL_OFF 0x0 ++#define RADIO_MIMO_CORESEL_CORE1 0x1 ++#define RADIO_MIMO_CORESEL_CORE2 0x2 ++#define RADIO_MIMO_CORESEL_CORE3 0x3 ++#define RADIO_MIMO_CORESEL_CORE4 0x4 ++#define RADIO_MIMO_CORESEL_ALLRX 0x5 ++#define RADIO_MIMO_CORESEL_ALLTX 0x6 ++#define RADIO_MIMO_CORESEL_ALLRXTX 0x7 ++ ++#define RADIO_2064_READ_OFF 0x200 ++ ++#define RADIO_2064_REG000 0x0 ++#define RADIO_2064_REG001 0x1 ++#define RADIO_2064_REG002 0x2 ++#define RADIO_2064_REG003 0x3 ++#define RADIO_2064_REG004 0x4 ++#define RADIO_2064_REG005 0x5 ++#define RADIO_2064_REG006 0x6 ++#define RADIO_2064_REG007 0x7 ++#define RADIO_2064_REG008 0x8 ++#define RADIO_2064_REG009 0x9 ++#define RADIO_2064_REG00A 0xa ++#define RADIO_2064_REG00B 0xb ++#define RADIO_2064_REG00C 0xc ++#define RADIO_2064_REG00D 0xd ++#define RADIO_2064_REG00E 0xe ++#define RADIO_2064_REG00F 0xf ++#define RADIO_2064_REG010 0x10 ++#define RADIO_2064_REG011 0x11 ++#define RADIO_2064_REG012 0x12 ++#define RADIO_2064_REG013 0x13 ++#define RADIO_2064_REG014 0x14 ++#define RADIO_2064_REG015 0x15 ++#define RADIO_2064_REG016 0x16 ++#define RADIO_2064_REG017 0x17 ++#define RADIO_2064_REG018 0x18 ++#define RADIO_2064_REG019 0x19 ++#define RADIO_2064_REG01A 0x1a ++#define RADIO_2064_REG01B 0x1b ++#define RADIO_2064_REG01C 0x1c ++#define RADIO_2064_REG01D 0x1d ++#define RADIO_2064_REG01E 0x1e ++#define RADIO_2064_REG01F 0x1f ++#define RADIO_2064_REG020 0x20 ++#define RADIO_2064_REG021 0x21 ++#define RADIO_2064_REG022 0x22 ++#define RADIO_2064_REG023 0x23 ++#define RADIO_2064_REG024 0x24 ++#define RADIO_2064_REG025 0x25 ++#define RADIO_2064_REG026 0x26 ++#define RADIO_2064_REG027 0x27 ++#define RADIO_2064_REG028 0x28 ++#define RADIO_2064_REG029 0x29 ++#define RADIO_2064_REG02A 0x2a ++#define RADIO_2064_REG02B 0x2b ++#define RADIO_2064_REG02C 0x2c ++#define RADIO_2064_REG02D 0x2d ++#define RADIO_2064_REG02E 0x2e ++#define RADIO_2064_REG02F 0x2f ++#define RADIO_2064_REG030 0x30 ++#define RADIO_2064_REG031 0x31 ++#define RADIO_2064_REG032 0x32 ++#define RADIO_2064_REG033 0x33 ++#define RADIO_2064_REG034 0x34 ++#define RADIO_2064_REG035 0x35 ++#define RADIO_2064_REG036 0x36 ++#define RADIO_2064_REG037 0x37 ++#define RADIO_2064_REG038 0x38 ++#define RADIO_2064_REG039 0x39 ++#define RADIO_2064_REG03A 0x3a ++#define RADIO_2064_REG03B 0x3b ++#define RADIO_2064_REG03C 0x3c ++#define RADIO_2064_REG03D 0x3d ++#define RADIO_2064_REG03E 0x3e ++#define RADIO_2064_REG03F 0x3f ++#define RADIO_2064_REG040 0x40 ++#define RADIO_2064_REG041 0x41 ++#define RADIO_2064_REG042 0x42 ++#define RADIO_2064_REG043 0x43 ++#define RADIO_2064_REG044 0x44 ++#define RADIO_2064_REG045 0x45 ++#define RADIO_2064_REG046 0x46 ++#define RADIO_2064_REG047 0x47 ++#define RADIO_2064_REG048 0x48 ++#define RADIO_2064_REG049 0x49 ++#define RADIO_2064_REG04A 0x4a ++#define RADIO_2064_REG04B 0x4b ++#define RADIO_2064_REG04C 0x4c ++#define RADIO_2064_REG04D 0x4d ++#define RADIO_2064_REG04E 0x4e ++#define RADIO_2064_REG04F 0x4f ++#define RADIO_2064_REG050 0x50 ++#define RADIO_2064_REG051 0x51 ++#define RADIO_2064_REG052 0x52 ++#define RADIO_2064_REG053 0x53 ++#define RADIO_2064_REG054 0x54 ++#define RADIO_2064_REG055 0x55 ++#define RADIO_2064_REG056 0x56 ++#define RADIO_2064_REG057 0x57 ++#define RADIO_2064_REG058 0x58 ++#define RADIO_2064_REG059 0x59 ++#define RADIO_2064_REG05A 0x5a ++#define RADIO_2064_REG05B 0x5b ++#define RADIO_2064_REG05C 0x5c ++#define RADIO_2064_REG05D 0x5d ++#define RADIO_2064_REG05E 0x5e ++#define RADIO_2064_REG05F 0x5f ++#define RADIO_2064_REG060 0x60 ++#define RADIO_2064_REG061 0x61 ++#define RADIO_2064_REG062 0x62 ++#define RADIO_2064_REG063 0x63 ++#define RADIO_2064_REG064 0x64 ++#define RADIO_2064_REG065 0x65 ++#define RADIO_2064_REG066 0x66 ++#define RADIO_2064_REG067 0x67 ++#define RADIO_2064_REG068 0x68 ++#define RADIO_2064_REG069 0x69 ++#define RADIO_2064_REG06A 0x6a ++#define RADIO_2064_REG06B 0x6b ++#define RADIO_2064_REG06C 0x6c ++#define RADIO_2064_REG06D 0x6d ++#define RADIO_2064_REG06E 0x6e ++#define RADIO_2064_REG06F 0x6f ++#define RADIO_2064_REG070 0x70 ++#define RADIO_2064_REG071 0x71 ++#define RADIO_2064_REG072 0x72 ++#define RADIO_2064_REG073 0x73 ++#define RADIO_2064_REG074 0x74 ++#define RADIO_2064_REG075 0x75 ++#define RADIO_2064_REG076 0x76 ++#define RADIO_2064_REG077 0x77 ++#define RADIO_2064_REG078 0x78 ++#define RADIO_2064_REG079 0x79 ++#define RADIO_2064_REG07A 0x7a ++#define RADIO_2064_REG07B 0x7b ++#define RADIO_2064_REG07C 0x7c ++#define RADIO_2064_REG07D 0x7d ++#define RADIO_2064_REG07E 0x7e ++#define RADIO_2064_REG07F 0x7f ++#define RADIO_2064_REG080 0x80 ++#define RADIO_2064_REG081 0x81 ++#define RADIO_2064_REG082 0x82 ++#define RADIO_2064_REG083 0x83 ++#define RADIO_2064_REG084 0x84 ++#define RADIO_2064_REG085 0x85 ++#define RADIO_2064_REG086 0x86 ++#define RADIO_2064_REG087 0x87 ++#define RADIO_2064_REG088 0x88 ++#define RADIO_2064_REG089 0x89 ++#define RADIO_2064_REG08A 0x8a ++#define RADIO_2064_REG08B 0x8b ++#define RADIO_2064_REG08C 0x8c ++#define RADIO_2064_REG08D 0x8d ++#define RADIO_2064_REG08E 0x8e ++#define RADIO_2064_REG08F 0x8f ++#define RADIO_2064_REG090 0x90 ++#define RADIO_2064_REG091 0x91 ++#define RADIO_2064_REG092 0x92 ++#define RADIO_2064_REG093 0x93 ++#define RADIO_2064_REG094 0x94 ++#define RADIO_2064_REG095 0x95 ++#define RADIO_2064_REG096 0x96 ++#define RADIO_2064_REG097 0x97 ++#define RADIO_2064_REG098 0x98 ++#define RADIO_2064_REG099 0x99 ++#define RADIO_2064_REG09A 0x9a ++#define RADIO_2064_REG09B 0x9b ++#define RADIO_2064_REG09C 0x9c ++#define RADIO_2064_REG09D 0x9d ++#define RADIO_2064_REG09E 0x9e ++#define RADIO_2064_REG09F 0x9f ++#define RADIO_2064_REG0A0 0xa0 ++#define RADIO_2064_REG0A1 0xa1 ++#define RADIO_2064_REG0A2 0xa2 ++#define RADIO_2064_REG0A3 0xa3 ++#define RADIO_2064_REG0A4 0xa4 ++#define RADIO_2064_REG0A5 0xa5 ++#define RADIO_2064_REG0A6 0xa6 ++#define RADIO_2064_REG0A7 0xa7 ++#define RADIO_2064_REG0A8 0xa8 ++#define RADIO_2064_REG0A9 0xa9 ++#define RADIO_2064_REG0AA 0xaa ++#define RADIO_2064_REG0AB 0xab ++#define RADIO_2064_REG0AC 0xac ++#define RADIO_2064_REG0AD 0xad ++#define RADIO_2064_REG0AE 0xae ++#define RADIO_2064_REG0AF 0xaf ++#define RADIO_2064_REG0B0 0xb0 ++#define RADIO_2064_REG0B1 0xb1 ++#define RADIO_2064_REG0B2 0xb2 ++#define RADIO_2064_REG0B3 0xb3 ++#define RADIO_2064_REG0B4 0xb4 ++#define RADIO_2064_REG0B5 0xb5 ++#define RADIO_2064_REG0B6 0xb6 ++#define RADIO_2064_REG0B7 0xb7 ++#define RADIO_2064_REG0B8 0xb8 ++#define RADIO_2064_REG0B9 0xb9 ++#define RADIO_2064_REG0BA 0xba ++#define RADIO_2064_REG0BB 0xbb ++#define RADIO_2064_REG0BC 0xbc ++#define RADIO_2064_REG0BD 0xbd ++#define RADIO_2064_REG0BE 0xbe ++#define RADIO_2064_REG0BF 0xbf ++#define RADIO_2064_REG0C0 0xc0 ++#define RADIO_2064_REG0C1 0xc1 ++#define RADIO_2064_REG0C2 0xc2 ++#define RADIO_2064_REG0C3 0xc3 ++#define RADIO_2064_REG0C4 0xc4 ++#define RADIO_2064_REG0C5 0xc5 ++#define RADIO_2064_REG0C6 0xc6 ++#define RADIO_2064_REG0C7 0xc7 ++#define RADIO_2064_REG0C8 0xc8 ++#define RADIO_2064_REG0C9 0xc9 ++#define RADIO_2064_REG0CA 0xca ++#define RADIO_2064_REG0CB 0xcb ++#define RADIO_2064_REG0CC 0xcc ++#define RADIO_2064_REG0CD 0xcd ++#define RADIO_2064_REG0CE 0xce ++#define RADIO_2064_REG0CF 0xcf ++#define RADIO_2064_REG0D0 0xd0 ++#define RADIO_2064_REG0D1 0xd1 ++#define RADIO_2064_REG0D2 0xd2 ++#define RADIO_2064_REG0D3 0xd3 ++#define RADIO_2064_REG0D4 0xd4 ++#define RADIO_2064_REG0D5 0xd5 ++#define RADIO_2064_REG0D6 0xd6 ++#define RADIO_2064_REG0D7 0xd7 ++#define RADIO_2064_REG0D8 0xd8 ++#define RADIO_2064_REG0D9 0xd9 ++#define RADIO_2064_REG0DA 0xda ++#define RADIO_2064_REG0DB 0xdb ++#define RADIO_2064_REG0DC 0xdc ++#define RADIO_2064_REG0DD 0xdd ++#define RADIO_2064_REG0DE 0xde ++#define RADIO_2064_REG0DF 0xdf ++#define RADIO_2064_REG0E0 0xe0 ++#define RADIO_2064_REG0E1 0xe1 ++#define RADIO_2064_REG0E2 0xe2 ++#define RADIO_2064_REG0E3 0xe3 ++#define RADIO_2064_REG0E4 0xe4 ++#define RADIO_2064_REG0E5 0xe5 ++#define RADIO_2064_REG0E6 0xe6 ++#define RADIO_2064_REG0E7 0xe7 ++#define RADIO_2064_REG0E8 0xe8 ++#define RADIO_2064_REG0E9 0xe9 ++#define RADIO_2064_REG0EA 0xea ++#define RADIO_2064_REG0EB 0xeb ++#define RADIO_2064_REG0EC 0xec ++#define RADIO_2064_REG0ED 0xed ++#define RADIO_2064_REG0EE 0xee ++#define RADIO_2064_REG0EF 0xef ++#define RADIO_2064_REG0F0 0xf0 ++#define RADIO_2064_REG0F1 0xf1 ++#define RADIO_2064_REG0F2 0xf2 ++#define RADIO_2064_REG0F3 0xf3 ++#define RADIO_2064_REG0F4 0xf4 ++#define RADIO_2064_REG0F5 0xf5 ++#define RADIO_2064_REG0F6 0xf6 ++#define RADIO_2064_REG0F7 0xf7 ++#define RADIO_2064_REG0F8 0xf8 ++#define RADIO_2064_REG0F9 0xf9 ++#define RADIO_2064_REG0FA 0xfa ++#define RADIO_2064_REG0FB 0xfb ++#define RADIO_2064_REG0FC 0xfc ++#define RADIO_2064_REG0FD 0xfd ++#define RADIO_2064_REG0FE 0xfe ++#define RADIO_2064_REG0FF 0xff ++#define RADIO_2064_REG100 0x100 ++#define RADIO_2064_REG101 0x101 ++#define RADIO_2064_REG102 0x102 ++#define RADIO_2064_REG103 0x103 ++#define RADIO_2064_REG104 0x104 ++#define RADIO_2064_REG105 0x105 ++#define RADIO_2064_REG106 0x106 ++#define RADIO_2064_REG107 0x107 ++#define RADIO_2064_REG108 0x108 ++#define RADIO_2064_REG109 0x109 ++#define RADIO_2064_REG10A 0x10a ++#define RADIO_2064_REG10B 0x10b ++#define RADIO_2064_REG10C 0x10c ++#define RADIO_2064_REG10D 0x10d ++#define RADIO_2064_REG10E 0x10e ++#define RADIO_2064_REG10F 0x10f ++#define RADIO_2064_REG110 0x110 ++#define RADIO_2064_REG111 0x111 ++#define RADIO_2064_REG112 0x112 ++#define RADIO_2064_REG113 0x113 ++#define RADIO_2064_REG114 0x114 ++#define RADIO_2064_REG115 0x115 ++#define RADIO_2064_REG116 0x116 ++#define RADIO_2064_REG117 0x117 ++#define RADIO_2064_REG118 0x118 ++#define RADIO_2064_REG119 0x119 ++#define RADIO_2064_REG11A 0x11a ++#define RADIO_2064_REG11B 0x11b ++#define RADIO_2064_REG11C 0x11c ++#define RADIO_2064_REG11D 0x11d ++#define RADIO_2064_REG11E 0x11e ++#define RADIO_2064_REG11F 0x11f ++#define RADIO_2064_REG120 0x120 ++#define RADIO_2064_REG121 0x121 ++#define RADIO_2064_REG122 0x122 ++#define RADIO_2064_REG123 0x123 ++#define RADIO_2064_REG124 0x124 ++#define RADIO_2064_REG125 0x125 ++#define RADIO_2064_REG126 0x126 ++#define RADIO_2064_REG127 0x127 ++#define RADIO_2064_REG128 0x128 ++#define RADIO_2064_REG129 0x129 ++#define RADIO_2064_REG12A 0x12a ++#define RADIO_2064_REG12B 0x12b ++#define RADIO_2064_REG12C 0x12c ++#define RADIO_2064_REG12D 0x12d ++#define RADIO_2064_REG12E 0x12e ++#define RADIO_2064_REG12F 0x12f ++#define RADIO_2064_REG130 0x130 ++ ++#define RADIO_2056_SYN (0x0 << 12) ++#define RADIO_2056_TX0 (0x2 << 12) ++#define RADIO_2056_TX1 (0x3 << 12) ++#define RADIO_2056_RX0 (0x6 << 12) ++#define RADIO_2056_RX1 (0x7 << 12) ++#define RADIO_2056_ALLTX (0xe << 12) ++#define RADIO_2056_ALLRX (0xf << 12) ++ ++#define RADIO_2056_SYN_RESERVED_ADDR0 0x0 ++#define RADIO_2056_SYN_IDCODE 0x1 ++#define RADIO_2056_SYN_RESERVED_ADDR2 0x2 ++#define RADIO_2056_SYN_RESERVED_ADDR3 0x3 ++#define RADIO_2056_SYN_RESERVED_ADDR4 0x4 ++#define RADIO_2056_SYN_RESERVED_ADDR5 0x5 ++#define RADIO_2056_SYN_RESERVED_ADDR6 0x6 ++#define RADIO_2056_SYN_RESERVED_ADDR7 0x7 ++#define RADIO_2056_SYN_COM_CTRL 0x8 ++#define RADIO_2056_SYN_COM_PU 0x9 ++#define RADIO_2056_SYN_COM_OVR 0xa ++#define RADIO_2056_SYN_COM_RESET 0xb ++#define RADIO_2056_SYN_COM_RCAL 0xc ++#define RADIO_2056_SYN_COM_RC_RXLPF 0xd ++#define RADIO_2056_SYN_COM_RC_TXLPF 0xe ++#define RADIO_2056_SYN_COM_RC_RXHPF 0xf ++#define RADIO_2056_SYN_RESERVED_ADDR16 0x10 ++#define RADIO_2056_SYN_RESERVED_ADDR17 0x11 ++#define RADIO_2056_SYN_RESERVED_ADDR18 0x12 ++#define RADIO_2056_SYN_RESERVED_ADDR19 0x13 ++#define RADIO_2056_SYN_RESERVED_ADDR20 0x14 ++#define RADIO_2056_SYN_RESERVED_ADDR21 0x15 ++#define RADIO_2056_SYN_RESERVED_ADDR22 0x16 ++#define RADIO_2056_SYN_RESERVED_ADDR23 0x17 ++#define RADIO_2056_SYN_RESERVED_ADDR24 0x18 ++#define RADIO_2056_SYN_RESERVED_ADDR25 0x19 ++#define RADIO_2056_SYN_RESERVED_ADDR26 0x1a ++#define RADIO_2056_SYN_RESERVED_ADDR27 0x1b ++#define RADIO_2056_SYN_RESERVED_ADDR28 0x1c ++#define RADIO_2056_SYN_RESERVED_ADDR29 0x1d ++#define RADIO_2056_SYN_RESERVED_ADDR30 0x1e ++#define RADIO_2056_SYN_RESERVED_ADDR31 0x1f ++#define RADIO_2056_SYN_GPIO_MASTER1 0x20 ++#define RADIO_2056_SYN_GPIO_MASTER2 0x21 ++#define RADIO_2056_SYN_TOPBIAS_MASTER 0x22 ++#define RADIO_2056_SYN_TOPBIAS_RCAL 0x23 ++#define RADIO_2056_SYN_AFEREG 0x24 ++#define RADIO_2056_SYN_TEMPPROCSENSE 0x25 ++#define RADIO_2056_SYN_TEMPPROCSENSEIDAC 0x26 ++#define RADIO_2056_SYN_TEMPPROCSENSERCAL 0x27 ++#define RADIO_2056_SYN_LPO 0x28 ++#define RADIO_2056_SYN_VDDCAL_MASTER 0x29 ++#define RADIO_2056_SYN_VDDCAL_IDAC 0x2a ++#define RADIO_2056_SYN_VDDCAL_STATUS 0x2b ++#define RADIO_2056_SYN_RCAL_MASTER 0x2c ++#define RADIO_2056_SYN_RCAL_CODE_OUT 0x2d ++#define RADIO_2056_SYN_RCCAL_CTRL0 0x2e ++#define RADIO_2056_SYN_RCCAL_CTRL1 0x2f ++#define RADIO_2056_SYN_RCCAL_CTRL2 0x30 ++#define RADIO_2056_SYN_RCCAL_CTRL3 0x31 ++#define RADIO_2056_SYN_RCCAL_CTRL4 0x32 ++#define RADIO_2056_SYN_RCCAL_CTRL5 0x33 ++#define RADIO_2056_SYN_RCCAL_CTRL6 0x34 ++#define RADIO_2056_SYN_RCCAL_CTRL7 0x35 ++#define RADIO_2056_SYN_RCCAL_CTRL8 0x36 ++#define RADIO_2056_SYN_RCCAL_CTRL9 0x37 ++#define RADIO_2056_SYN_RCCAL_CTRL10 0x38 ++#define RADIO_2056_SYN_RCCAL_CTRL11 0x39 ++#define RADIO_2056_SYN_ZCAL_SPARE1 0x3a ++#define RADIO_2056_SYN_ZCAL_SPARE2 0x3b ++#define RADIO_2056_SYN_PLL_MAST1 0x3c ++#define RADIO_2056_SYN_PLL_MAST2 0x3d ++#define RADIO_2056_SYN_PLL_MAST3 0x3e ++#define RADIO_2056_SYN_PLL_BIAS_RESET 0x3f ++#define RADIO_2056_SYN_PLL_XTAL0 0x40 ++#define RADIO_2056_SYN_PLL_XTAL1 0x41 ++#define RADIO_2056_SYN_PLL_XTAL3 0x42 ++#define RADIO_2056_SYN_PLL_XTAL4 0x43 ++#define RADIO_2056_SYN_PLL_XTAL5 0x44 ++#define RADIO_2056_SYN_PLL_XTAL6 0x45 ++#define RADIO_2056_SYN_PLL_REFDIV 0x46 ++#define RADIO_2056_SYN_PLL_PFD 0x47 ++#define RADIO_2056_SYN_PLL_CP1 0x48 ++#define RADIO_2056_SYN_PLL_CP2 0x49 ++#define RADIO_2056_SYN_PLL_CP3 0x4a ++#define RADIO_2056_SYN_PLL_LOOPFILTER1 0x4b ++#define RADIO_2056_SYN_PLL_LOOPFILTER2 0x4c ++#define RADIO_2056_SYN_PLL_LOOPFILTER3 0x4d ++#define RADIO_2056_SYN_PLL_LOOPFILTER4 0x4e ++#define RADIO_2056_SYN_PLL_LOOPFILTER5 0x4f ++#define RADIO_2056_SYN_PLL_MMD1 0x50 ++#define RADIO_2056_SYN_PLL_MMD2 0x51 ++#define RADIO_2056_SYN_PLL_VCO1 0x52 ++#define RADIO_2056_SYN_PLL_VCO2 0x53 ++#define RADIO_2056_SYN_PLL_MONITOR1 0x54 ++#define RADIO_2056_SYN_PLL_MONITOR2 0x55 ++#define RADIO_2056_SYN_PLL_VCOCAL1 0x56 ++#define RADIO_2056_SYN_PLL_VCOCAL2 0x57 ++#define RADIO_2056_SYN_PLL_VCOCAL4 0x58 ++#define RADIO_2056_SYN_PLL_VCOCAL5 0x59 ++#define RADIO_2056_SYN_PLL_VCOCAL6 0x5a ++#define RADIO_2056_SYN_PLL_VCOCAL7 0x5b ++#define RADIO_2056_SYN_PLL_VCOCAL8 0x5c ++#define RADIO_2056_SYN_PLL_VCOCAL9 0x5d ++#define RADIO_2056_SYN_PLL_VCOCAL10 0x5e ++#define RADIO_2056_SYN_PLL_VCOCAL11 0x5f ++#define RADIO_2056_SYN_PLL_VCOCAL12 0x60 ++#define RADIO_2056_SYN_PLL_VCOCAL13 0x61 ++#define RADIO_2056_SYN_PLL_VREG 0x62 ++#define RADIO_2056_SYN_PLL_STATUS1 0x63 ++#define RADIO_2056_SYN_PLL_STATUS2 0x64 ++#define RADIO_2056_SYN_PLL_STATUS3 0x65 ++#define RADIO_2056_SYN_LOGEN_PU0 0x66 ++#define RADIO_2056_SYN_LOGEN_PU1 0x67 ++#define RADIO_2056_SYN_LOGEN_PU2 0x68 ++#define RADIO_2056_SYN_LOGEN_PU3 0x69 ++#define RADIO_2056_SYN_LOGEN_PU5 0x6a ++#define RADIO_2056_SYN_LOGEN_PU6 0x6b ++#define RADIO_2056_SYN_LOGEN_PU7 0x6c ++#define RADIO_2056_SYN_LOGEN_PU8 0x6d ++#define RADIO_2056_SYN_LOGEN_BIAS_RESET 0x6e ++#define RADIO_2056_SYN_LOGEN_RCCR1 0x6f ++#define RADIO_2056_SYN_LOGEN_VCOBUF1 0x70 ++#define RADIO_2056_SYN_LOGEN_MIXER1 0x71 ++#define RADIO_2056_SYN_LOGEN_MIXER2 0x72 ++#define RADIO_2056_SYN_LOGEN_BUF1 0x73 ++#define RADIO_2056_SYN_LOGENBUF2 0x74 ++#define RADIO_2056_SYN_LOGEN_BUF3 0x75 ++#define RADIO_2056_SYN_LOGEN_BUF4 0x76 ++#define RADIO_2056_SYN_LOGEN_DIV1 0x77 ++#define RADIO_2056_SYN_LOGEN_DIV2 0x78 ++#define RADIO_2056_SYN_LOGEN_DIV3 0x79 ++#define RADIO_2056_SYN_LOGEN_ACL1 0x7a ++#define RADIO_2056_SYN_LOGEN_ACL2 0x7b ++#define RADIO_2056_SYN_LOGEN_ACL3 0x7c ++#define RADIO_2056_SYN_LOGEN_ACL4 0x7d ++#define RADIO_2056_SYN_LOGEN_ACL5 0x7e ++#define RADIO_2056_SYN_LOGEN_ACL6 0x7f ++#define RADIO_2056_SYN_LOGEN_ACLOUT 0x80 ++#define RADIO_2056_SYN_LOGEN_ACLCAL1 0x81 ++#define RADIO_2056_SYN_LOGEN_ACLCAL2 0x82 ++#define RADIO_2056_SYN_LOGEN_ACLCAL3 0x83 ++#define RADIO_2056_SYN_CALEN 0x84 ++#define RADIO_2056_SYN_LOGEN_PEAKDET1 0x85 ++#define RADIO_2056_SYN_LOGEN_CORE_ACL_OVR 0x86 ++#define RADIO_2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87 ++#define RADIO_2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88 ++#define RADIO_2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89 ++#define RADIO_2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8a ++#define RADIO_2056_SYN_LOGEN_VCOBUF2 0x8b ++#define RADIO_2056_SYN_LOGEN_MIXER3 0x8c ++#define RADIO_2056_SYN_LOGEN_BUF5 0x8d ++#define RADIO_2056_SYN_LOGEN_BUF6 0x8e ++#define RADIO_2056_SYN_LOGEN_CBUFRX1 0x8f ++#define RADIO_2056_SYN_LOGEN_CBUFRX2 0x90 ++#define RADIO_2056_SYN_LOGEN_CBUFRX3 0x91 ++#define RADIO_2056_SYN_LOGEN_CBUFRX4 0x92 ++#define RADIO_2056_SYN_LOGEN_CBUFTX1 0x93 ++#define RADIO_2056_SYN_LOGEN_CBUFTX2 0x94 ++#define RADIO_2056_SYN_LOGEN_CBUFTX3 0x95 ++#define RADIO_2056_SYN_LOGEN_CBUFTX4 0x96 ++#define RADIO_2056_SYN_LOGEN_CMOSRX1 0x97 ++#define RADIO_2056_SYN_LOGEN_CMOSRX2 0x98 ++#define RADIO_2056_SYN_LOGEN_CMOSRX3 0x99 ++#define RADIO_2056_SYN_LOGEN_CMOSRX4 0x9a ++#define RADIO_2056_SYN_LOGEN_CMOSTX1 0x9b ++#define RADIO_2056_SYN_LOGEN_CMOSTX2 0x9c ++#define RADIO_2056_SYN_LOGEN_CMOSTX3 0x9d ++#define RADIO_2056_SYN_LOGEN_CMOSTX4 0x9e ++#define RADIO_2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9f ++#define RADIO_2056_SYN_LOGEN_MIXER3_OVRVAL 0xa0 ++#define RADIO_2056_SYN_LOGEN_BUF5_OVRVAL 0xa1 ++#define RADIO_2056_SYN_LOGEN_BUF6_OVRVAL 0xa2 ++#define RADIO_2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xa3 ++#define RADIO_2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xa4 ++#define RADIO_2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xa5 ++#define RADIO_2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xa6 ++#define RADIO_2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xa7 ++#define RADIO_2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xa8 ++#define RADIO_2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xa9 ++#define RADIO_2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xaa ++#define RADIO_2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xab ++#define RADIO_2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xac ++#define RADIO_2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xad ++#define RADIO_2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xae ++#define RADIO_2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xaf ++#define RADIO_2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xb0 ++#define RADIO_2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xb1 ++#define RADIO_2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xb2 ++#define RADIO_2056_SYN_LOGEN_ACL_WAITCNT 0xb3 ++#define RADIO_2056_SYN_LOGEN_CORE_CALVALID 0xb4 ++#define RADIO_2056_SYN_LOGEN_RX_CMOS_CALVALID 0xb5 ++#define RADIO_2056_SYN_LOGEN_TX_CMOS_VALID 0xb6 ++ ++#define RADIO_2056_TX_RESERVED_ADDR0 0x0 ++#define RADIO_2056_TX_IDCODE 0x1 ++#define RADIO_2056_TX_RESERVED_ADDR2 0x2 ++#define RADIO_2056_TX_RESERVED_ADDR3 0x3 ++#define RADIO_2056_TX_RESERVED_ADDR4 0x4 ++#define RADIO_2056_TX_RESERVED_ADDR5 0x5 ++#define RADIO_2056_TX_RESERVED_ADDR6 0x6 ++#define RADIO_2056_TX_RESERVED_ADDR7 0x7 ++#define RADIO_2056_TX_COM_CTRL 0x8 ++#define RADIO_2056_TX_COM_PU 0x9 ++#define RADIO_2056_TX_COM_OVR 0xa ++#define RADIO_2056_TX_COM_RESET 0xb ++#define RADIO_2056_TX_COM_RCAL 0xc ++#define RADIO_2056_TX_COM_RC_RXLPF 0xd ++#define RADIO_2056_TX_COM_RC_TXLPF 0xe ++#define RADIO_2056_TX_COM_RC_RXHPF 0xf ++#define RADIO_2056_TX_RESERVED_ADDR16 0x10 ++#define RADIO_2056_TX_RESERVED_ADDR17 0x11 ++#define RADIO_2056_TX_RESERVED_ADDR18 0x12 ++#define RADIO_2056_TX_RESERVED_ADDR19 0x13 ++#define RADIO_2056_TX_RESERVED_ADDR20 0x14 ++#define RADIO_2056_TX_RESERVED_ADDR21 0x15 ++#define RADIO_2056_TX_RESERVED_ADDR22 0x16 ++#define RADIO_2056_TX_RESERVED_ADDR23 0x17 ++#define RADIO_2056_TX_RESERVED_ADDR24 0x18 ++#define RADIO_2056_TX_RESERVED_ADDR25 0x19 ++#define RADIO_2056_TX_RESERVED_ADDR26 0x1a ++#define RADIO_2056_TX_RESERVED_ADDR27 0x1b ++#define RADIO_2056_TX_RESERVED_ADDR28 0x1c ++#define RADIO_2056_TX_RESERVED_ADDR29 0x1d ++#define RADIO_2056_TX_RESERVED_ADDR30 0x1e ++#define RADIO_2056_TX_RESERVED_ADDR31 0x1f ++#define RADIO_2056_TX_IQCAL_GAIN_BW 0x20 ++#define RADIO_2056_TX_LOFT_FINE_I 0x21 ++#define RADIO_2056_TX_LOFT_FINE_Q 0x22 ++#define RADIO_2056_TX_LOFT_COARSE_I 0x23 ++#define RADIO_2056_TX_LOFT_COARSE_Q 0x24 ++#define RADIO_2056_TX_TX_COM_MASTER1 0x25 ++#define RADIO_2056_TX_TX_COM_MASTER2 0x26 ++#define RADIO_2056_TX_RXIQCAL_TXMUX 0x27 ++#define RADIO_2056_TX_TX_SSI_MASTER 0x28 ++#define RADIO_2056_TX_IQCAL_VCM_HG 0x29 ++#define RADIO_2056_TX_IQCAL_IDAC 0x2a ++#define RADIO_2056_TX_TSSI_VCM 0x2b ++#define RADIO_2056_TX_TX_AMP_DET 0x2c ++#define RADIO_2056_TX_TX_SSI_MUX 0x2d ++#define RADIO_2056_TX_TSSIA 0x2e ++#define RADIO_2056_TX_TSSIG 0x2f ++#define RADIO_2056_TX_TSSI_MISC1 0x30 ++#define RADIO_2056_TX_TSSI_MISC2 0x31 ++#define RADIO_2056_TX_TSSI_MISC3 0x32 ++#define RADIO_2056_TX_PA_SPARE1 0x33 ++#define RADIO_2056_TX_PA_SPARE2 0x34 ++#define RADIO_2056_TX_INTPAA_MASTER 0x35 ++#define RADIO_2056_TX_INTPAA_GAIN 0x36 ++#define RADIO_2056_TX_INTPAA_BOOST_TUNE 0x37 ++#define RADIO_2056_TX_INTPAA_IAUX_STAT 0x38 ++#define RADIO_2056_TX_INTPAA_IAUX_DYN 0x39 ++#define RADIO_2056_TX_INTPAA_IMAIN_STAT 0x3a ++#define RADIO_2056_TX_INTPAA_IMAIN_DYN 0x3b ++#define RADIO_2056_TX_INTPAA_CASCBIAS 0x3c ++#define RADIO_2056_TX_INTPAA_PASLOPE 0x3d ++#define RADIO_2056_TX_INTPAA_PA_MISC 0x3e ++#define RADIO_2056_TX_INTPAG_MASTER 0x3f ++#define RADIO_2056_TX_INTPAG_GAIN 0x40 ++#define RADIO_2056_TX_INTPAG_BOOST_TUNE 0x41 ++#define RADIO_2056_TX_INTPAG_IAUX_STAT 0x42 ++#define RADIO_2056_TX_INTPAG_IAUX_DYN 0x43 ++#define RADIO_2056_TX_INTPAG_IMAIN_STAT 0x44 ++#define RADIO_2056_TX_INTPAG_IMAIN_DYN 0x45 ++#define RADIO_2056_TX_INTPAG_CASCBIAS 0x46 ++#define RADIO_2056_TX_INTPAG_PASLOPE 0x47 ++#define RADIO_2056_TX_INTPAG_PA_MISC 0x48 ++#define RADIO_2056_TX_PADA_MASTER 0x49 ++#define RADIO_2056_TX_PADA_IDAC 0x4a ++#define RADIO_2056_TX_PADA_CASCBIAS 0x4b ++#define RADIO_2056_TX_PADA_GAIN 0x4c ++#define RADIO_2056_TX_PADA_BOOST_TUNE 0x4d ++#define RADIO_2056_TX_PADA_SLOPE 0x4e ++#define RADIO_2056_TX_PADG_MASTER 0x4f ++#define RADIO_2056_TX_PADG_IDAC 0x50 ++#define RADIO_2056_TX_PADG_CASCBIAS 0x51 ++#define RADIO_2056_TX_PADG_GAIN 0x52 ++#define RADIO_2056_TX_PADG_BOOST_TUNE 0x53 ++#define RADIO_2056_TX_PADG_SLOPE 0x54 ++#define RADIO_2056_TX_PGAA_MASTER 0x55 ++#define RADIO_2056_TX_PGAA_IDAC 0x56 ++#define RADIO_2056_TX_PGAA_GAIN 0x57 ++#define RADIO_2056_TX_PGAA_BOOST_TUNE 0x58 ++#define RADIO_2056_TX_PGAA_SLOPE 0x59 ++#define RADIO_2056_TX_PGAA_MISC 0x5a ++#define RADIO_2056_TX_PGAG_MASTER 0x5b ++#define RADIO_2056_TX_PGAG_IDAC 0x5c ++#define RADIO_2056_TX_PGAG_GAIN 0x5d ++#define RADIO_2056_TX_PGAG_BOOST_TUNE 0x5e ++#define RADIO_2056_TX_PGAG_SLOPE 0x5f ++#define RADIO_2056_TX_PGAG_MISC 0x60 ++#define RADIO_2056_TX_MIXA_MASTER 0x61 ++#define RADIO_2056_TX_MIXA_BOOST_TUNE 0x62 ++#define RADIO_2056_TX_MIXG 0x63 ++#define RADIO_2056_TX_MIXG_BOOST_TUNE 0x64 ++#define RADIO_2056_TX_BB_GM_MASTER 0x65 ++#define RADIO_2056_TX_GMBB_GM 0x66 ++#define RADIO_2056_TX_GMBB_IDAC 0x67 ++#define RADIO_2056_TX_TXLPF_MASTER 0x68 ++#define RADIO_2056_TX_TXLPF_RCCAL 0x69 ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF0 0x6a ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF1 0x6b ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF2 0x6c ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF3 0x6d ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF4 0x6e ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF5 0x6f ++#define RADIO_2056_TX_TXLPF_RCCAL_OFF6 0x70 ++#define RADIO_2056_TX_TXLPF_BW 0x71 ++#define RADIO_2056_TX_TXLPF_GAIN 0x72 ++#define RADIO_2056_TX_TXLPF_IDAC 0x73 ++#define RADIO_2056_TX_TXLPF_IDAC_0 0x74 ++#define RADIO_2056_TX_TXLPF_IDAC_1 0x75 ++#define RADIO_2056_TX_TXLPF_IDAC_2 0x76 ++#define RADIO_2056_TX_TXLPF_IDAC_3 0x77 ++#define RADIO_2056_TX_TXLPF_IDAC_4 0x78 ++#define RADIO_2056_TX_TXLPF_IDAC_5 0x79 ++#define RADIO_2056_TX_TXLPF_IDAC_6 0x7a ++#define RADIO_2056_TX_TXLPF_OPAMP_IDAC 0x7b ++#define RADIO_2056_TX_TXLPF_MISC 0x7c ++#define RADIO_2056_TX_TXSPARE1 0x7d ++#define RADIO_2056_TX_TXSPARE2 0x7e ++#define RADIO_2056_TX_TXSPARE3 0x7f ++#define RADIO_2056_TX_TXSPARE4 0x80 ++#define RADIO_2056_TX_TXSPARE5 0x81 ++#define RADIO_2056_TX_TXSPARE6 0x82 ++#define RADIO_2056_TX_TXSPARE7 0x83 ++#define RADIO_2056_TX_TXSPARE8 0x84 ++#define RADIO_2056_TX_TXSPARE9 0x85 ++#define RADIO_2056_TX_TXSPARE10 0x86 ++#define RADIO_2056_TX_TXSPARE11 0x87 ++#define RADIO_2056_TX_TXSPARE12 0x88 ++#define RADIO_2056_TX_TXSPARE13 0x89 ++#define RADIO_2056_TX_TXSPARE14 0x8a ++#define RADIO_2056_TX_TXSPARE15 0x8b ++#define RADIO_2056_TX_TXSPARE16 0x8c ++#define RADIO_2056_TX_STATUS_INTPA_GAIN 0x8d ++#define RADIO_2056_TX_STATUS_PAD_GAIN 0x8e ++#define RADIO_2056_TX_STATUS_PGA_GAIN 0x8f ++#define RADIO_2056_TX_STATUS_GM_TXLPF_GAIN 0x90 ++#define RADIO_2056_TX_STATUS_TXLPF_BW 0x91 ++#define RADIO_2056_TX_STATUS_TXLPF_RC 0x92 ++#define RADIO_2056_TX_GMBB_IDAC0 0x93 ++#define RADIO_2056_TX_GMBB_IDAC1 0x94 ++#define RADIO_2056_TX_GMBB_IDAC2 0x95 ++#define RADIO_2056_TX_GMBB_IDAC3 0x96 ++#define RADIO_2056_TX_GMBB_IDAC4 0x97 ++#define RADIO_2056_TX_GMBB_IDAC5 0x98 ++#define RADIO_2056_TX_GMBB_IDAC6 0x99 ++#define RADIO_2056_TX_GMBB_IDAC7 0x9a ++ ++#define RADIO_2056_RX_RESERVED_ADDR0 0x0 ++#define RADIO_2056_RX_IDCODE 0x1 ++#define RADIO_2056_RX_RESERVED_ADDR2 0x2 ++#define RADIO_2056_RX_RESERVED_ADDR3 0x3 ++#define RADIO_2056_RX_RESERVED_ADDR4 0x4 ++#define RADIO_2056_RX_RESERVED_ADDR5 0x5 ++#define RADIO_2056_RX_RESERVED_ADDR6 0x6 ++#define RADIO_2056_RX_RESERVED_ADDR7 0x7 ++#define RADIO_2056_RX_COM_CTRL 0x8 ++#define RADIO_2056_RX_COM_PU 0x9 ++#define RADIO_2056_RX_COM_OVR 0xa ++#define RADIO_2056_RX_COM_RESET 0xb ++#define RADIO_2056_RX_COM_RCAL 0xc ++#define RADIO_2056_RX_COM_RC_RXLPF 0xd ++#define RADIO_2056_RX_COM_RC_TXLPF 0xe ++#define RADIO_2056_RX_COM_RC_RXHPF 0xf ++#define RADIO_2056_RX_RESERVED_ADDR16 0x10 ++#define RADIO_2056_RX_RESERVED_ADDR17 0x11 ++#define RADIO_2056_RX_RESERVED_ADDR18 0x12 ++#define RADIO_2056_RX_RESERVED_ADDR19 0x13 ++#define RADIO_2056_RX_RESERVED_ADDR20 0x14 ++#define RADIO_2056_RX_RESERVED_ADDR21 0x15 ++#define RADIO_2056_RX_RESERVED_ADDR22 0x16 ++#define RADIO_2056_RX_RESERVED_ADDR23 0x17 ++#define RADIO_2056_RX_RESERVED_ADDR24 0x18 ++#define RADIO_2056_RX_RESERVED_ADDR25 0x19 ++#define RADIO_2056_RX_RESERVED_ADDR26 0x1a ++#define RADIO_2056_RX_RESERVED_ADDR27 0x1b ++#define RADIO_2056_RX_RESERVED_ADDR28 0x1c ++#define RADIO_2056_RX_RESERVED_ADDR29 0x1d ++#define RADIO_2056_RX_RESERVED_ADDR30 0x1e ++#define RADIO_2056_RX_RESERVED_ADDR31 0x1f ++#define RADIO_2056_RX_RXIQCAL_RXMUX 0x20 ++#define RADIO_2056_RX_RSSI_PU 0x21 ++#define RADIO_2056_RX_RSSI_SEL 0x22 ++#define RADIO_2056_RX_RSSI_GAIN 0x23 ++#define RADIO_2056_RX_RSSI_NB_IDAC 0x24 ++#define RADIO_2056_RX_RSSI_WB2I_IDAC_1 0x25 ++#define RADIO_2056_RX_RSSI_WB2I_IDAC_2 0x26 ++#define RADIO_2056_RX_RSSI_WB2Q_IDAC_1 0x27 ++#define RADIO_2056_RX_RSSI_WB2Q_IDAC_2 0x28 ++#define RADIO_2056_RX_RSSI_POLE 0x29 ++#define RADIO_2056_RX_RSSI_WB1_IDAC 0x2a ++#define RADIO_2056_RX_RSSI_MISC 0x2b ++#define RADIO_2056_RX_LNAA_MASTER 0x2c ++#define RADIO_2056_RX_LNAA_TUNE 0x2d ++#define RADIO_2056_RX_LNAA_GAIN 0x2e ++#define RADIO_2056_RX_LNA_A_SLOPE 0x2f ++#define RADIO_2056_RX_BIASPOLE_LNAA1_IDAC 0x30 ++#define RADIO_2056_RX_LNAA2_IDAC 0x31 ++#define RADIO_2056_RX_LNA1A_MISC 0x32 ++#define RADIO_2056_RX_LNAG_MASTER 0x33 ++#define RADIO_2056_RX_LNAG_TUNE 0x34 ++#define RADIO_2056_RX_LNAG_GAIN 0x35 ++#define RADIO_2056_RX_LNA_G_SLOPE 0x36 ++#define RADIO_2056_RX_BIASPOLE_LNAG1_IDAC 0x37 ++#define RADIO_2056_RX_LNAG2_IDAC 0x38 ++#define RADIO_2056_RX_LNA1G_MISC 0x39 ++#define RADIO_2056_RX_MIXA_MASTER 0x3a ++#define RADIO_2056_RX_MIXA_VCM 0x3b ++#define RADIO_2056_RX_MIXA_CTRLPTAT 0x3c ++#define RADIO_2056_RX_MIXA_LOB_BIAS 0x3d ++#define RADIO_2056_RX_MIXA_CORE_IDAC 0x3e ++#define RADIO_2056_RX_MIXA_CMFB_IDAC 0x3f ++#define RADIO_2056_RX_MIXA_BIAS_AUX 0x40 ++#define RADIO_2056_RX_MIXA_BIAS_MAIN 0x41 ++#define RADIO_2056_RX_MIXA_BIAS_MISC 0x42 ++#define RADIO_2056_RX_MIXA_MAST_BIAS 0x43 ++#define RADIO_2056_RX_MIXG_MASTER 0x44 ++#define RADIO_2056_RX_MIXG_VCM 0x45 ++#define RADIO_2056_RX_MIXG_CTRLPTAT 0x46 ++#define RADIO_2056_RX_MIXG_LOB_BIAS 0x47 ++#define RADIO_2056_RX_MIXG_CORE_IDAC 0x48 ++#define RADIO_2056_RX_MIXG_CMFB_IDAC 0x49 ++#define RADIO_2056_RX_MIXG_BIAS_AUX 0x4a ++#define RADIO_2056_RX_MIXG_BIAS_MAIN 0x4b ++#define RADIO_2056_RX_MIXG_BIAS_MISC 0x4c ++#define RADIO_2056_RX_MIXG_MAST_BIAS 0x4d ++#define RADIO_2056_RX_TIA_MASTER 0x4e ++#define RADIO_2056_RX_TIA_IOPAMP 0x4f ++#define RADIO_2056_RX_TIA_QOPAMP 0x50 ++#define RADIO_2056_RX_TIA_IMISC 0x51 ++#define RADIO_2056_RX_TIA_QMISC 0x52 ++#define RADIO_2056_RX_TIA_GAIN 0x53 ++#define RADIO_2056_RX_TIA_SPARE1 0x54 ++#define RADIO_2056_RX_TIA_SPARE2 0x55 ++#define RADIO_2056_RX_BB_LPF_MASTER 0x56 ++#define RADIO_2056_RX_AACI_MASTER 0x57 ++#define RADIO_2056_RX_RXLPF_IDAC 0x58 ++#define RADIO_2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59 ++#define RADIO_2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5a ++#define RADIO_2056_RX_RXLPF_BIAS_DCCANCEL 0x5b ++#define RADIO_2056_RX_RXLPF_OUTVCM 0x5c ++#define RADIO_2056_RX_RXLPF_INVCM_BODY 0x5d ++#define RADIO_2056_RX_RXLPF_CC_OP 0x5e ++#define RADIO_2056_RX_RXLPF_GAIN 0x5f ++#define RADIO_2056_RX_RXLPF_Q_BW 0x60 ++#define RADIO_2056_RX_RXLPF_HP_CORNER_BW 0x61 ++#define RADIO_2056_RX_RXLPF_RCCAL_HPC 0x62 ++#define RADIO_2056_RX_RXHPF_OFF0 0x63 ++#define RADIO_2056_RX_RXHPF_OFF1 0x64 ++#define RADIO_2056_RX_RXHPF_OFF2 0x65 ++#define RADIO_2056_RX_RXHPF_OFF3 0x66 ++#define RADIO_2056_RX_RXHPF_OFF4 0x67 ++#define RADIO_2056_RX_RXHPF_OFF5 0x68 ++#define RADIO_2056_RX_RXHPF_OFF6 0x69 ++#define RADIO_2056_RX_RXHPF_OFF7 0x6a ++#define RADIO_2056_RX_RXLPF_RCCAL_LPC 0x6b ++#define RADIO_2056_RX_RXLPF_OFF_0 0x6c ++#define RADIO_2056_RX_RXLPF_OFF_1 0x6d ++#define RADIO_2056_RX_RXLPF_OFF_2 0x6e ++#define RADIO_2056_RX_RXLPF_OFF_3 0x6f ++#define RADIO_2056_RX_RXLPF_OFF_4 0x70 ++#define RADIO_2056_RX_UNUSED 0x71 ++#define RADIO_2056_RX_VGA_MASTER 0x72 ++#define RADIO_2056_RX_VGA_BIAS 0x73 ++#define RADIO_2056_RX_VGA_BIAS_DCCANCEL 0x74 ++#define RADIO_2056_RX_VGA_GAIN 0x75 ++#define RADIO_2056_RX_VGA_HP_CORNER_BW 0x76 ++#define RADIO_2056_RX_VGABUF_BIAS 0x77 ++#define RADIO_2056_RX_VGABUF_GAIN_BW 0x78 ++#define RADIO_2056_RX_TXFBMIX_A 0x79 ++#define RADIO_2056_RX_TXFBMIX_G 0x7a ++#define RADIO_2056_RX_RXSPARE1 0x7b ++#define RADIO_2056_RX_RXSPARE2 0x7c ++#define RADIO_2056_RX_RXSPARE3 0x7d ++#define RADIO_2056_RX_RXSPARE4 0x7e ++#define RADIO_2056_RX_RXSPARE5 0x7f ++#define RADIO_2056_RX_RXSPARE6 0x80 ++#define RADIO_2056_RX_RXSPARE7 0x81 ++#define RADIO_2056_RX_RXSPARE8 0x82 ++#define RADIO_2056_RX_RXSPARE9 0x83 ++#define RADIO_2056_RX_RXSPARE10 0x84 ++#define RADIO_2056_RX_RXSPARE11 0x85 ++#define RADIO_2056_RX_RXSPARE12 0x86 ++#define RADIO_2056_RX_RXSPARE13 0x87 ++#define RADIO_2056_RX_RXSPARE14 0x88 ++#define RADIO_2056_RX_RXSPARE15 0x89 ++#define RADIO_2056_RX_RXSPARE16 0x8a ++#define RADIO_2056_RX_STATUS_LNAA_GAIN 0x8b ++#define RADIO_2056_RX_STATUS_LNAG_GAIN 0x8c ++#define RADIO_2056_RX_STATUS_MIXTIA_GAIN 0x8d ++#define RADIO_2056_RX_STATUS_RXLPF_GAIN 0x8e ++#define RADIO_2056_RX_STATUS_VGA_BUF_GAIN 0x8f ++#define RADIO_2056_RX_STATUS_RXLPF_Q 0x90 ++#define RADIO_2056_RX_STATUS_RXLPF_BUF_BW 0x91 ++#define RADIO_2056_RX_STATUS_RXLPF_VGA_HPC 0x92 ++#define RADIO_2056_RX_STATUS_RXLPF_RC 0x93 ++#define RADIO_2056_RX_STATUS_HPC_RC 0x94 ++ ++#define RADIO_2056_LNA1_A_PU 0x01 ++#define RADIO_2056_LNA2_A_PU 0x02 ++#define RADIO_2056_LNA1_G_PU 0x01 ++#define RADIO_2056_LNA2_G_PU 0x02 ++#define RADIO_2056_MIXA_PU_I 0x01 ++#define RADIO_2056_MIXA_PU_Q 0x02 ++#define RADIO_2056_MIXA_PU_GM 0x10 ++#define RADIO_2056_MIXG_PU_I 0x01 ++#define RADIO_2056_MIXG_PU_Q 0x02 ++#define RADIO_2056_MIXG_PU_GM 0x10 ++#define RADIO_2056_TIA_PU 0x01 ++#define RADIO_2056_BB_LPF_PU 0x20 ++#define RADIO_2056_W1_PU 0x02 ++#define RADIO_2056_W2_PU 0x04 ++#define RADIO_2056_NB_PU 0x08 ++#define RADIO_2056_RSSI_W1_SEL 0x02 ++#define RADIO_2056_RSSI_W2_SEL 0x04 ++#define RADIO_2056_RSSI_NB_SEL 0x08 ++#define RADIO_2056_VCM_MASK 0x1c ++#define RADIO_2056_RSSI_VCM_SHIFT 0x02 ++ ++#define RADIO_2057_DACBUF_VINCM_CORE0 0x0 ++#define RADIO_2057_IDCODE 0x1 ++#define RADIO_2057_RCCAL_MASTER 0x2 ++#define RADIO_2057_RCCAL_CAP_SIZE 0x3 ++#define RADIO_2057_RCAL_CONFIG 0x4 ++#define RADIO_2057_GPAIO_CONFIG 0x5 ++#define RADIO_2057_GPAIO_SEL1 0x6 ++#define RADIO_2057_GPAIO_SEL0 0x7 ++#define RADIO_2057_CLPO_CONFIG 0x8 ++#define RADIO_2057_BANDGAP_CONFIG 0x9 ++#define RADIO_2057_BANDGAP_RCAL_TRIM 0xa ++#define RADIO_2057_AFEREG_CONFIG 0xb ++#define RADIO_2057_TEMPSENSE_CONFIG 0xc ++#define RADIO_2057_XTAL_CONFIG1 0xd ++#define RADIO_2057_XTAL_ICORE_SIZE 0xe ++#define RADIO_2057_XTAL_BUF_SIZE 0xf ++#define RADIO_2057_XTAL_PULLCAP_SIZE 0x10 ++#define RADIO_2057_RFPLL_MASTER 0x11 ++#define RADIO_2057_VCOMONITOR_VTH_L 0x12 ++#define RADIO_2057_VCOMONITOR_VTH_H 0x13 ++#define RADIO_2057_VCOCAL_BIASRESET_RFPLLREG_VOUT 0x14 ++#define RADIO_2057_VCO_VARCSIZE_IDAC 0x15 ++#define RADIO_2057_VCOCAL_COUNTVAL0 0x16 ++#define RADIO_2057_VCOCAL_COUNTVAL1 0x17 ++#define RADIO_2057_VCOCAL_INTCLK_COUNT 0x18 ++#define RADIO_2057_VCOCAL_MASTER 0x19 ++#define RADIO_2057_VCOCAL_NUMCAPCHANGE 0x1a ++#define RADIO_2057_VCOCAL_WINSIZE 0x1b ++#define RADIO_2057_VCOCAL_DELAY_AFTER_REFRESH 0x1c ++#define RADIO_2057_VCOCAL_DELAY_AFTER_CLOSELOOP 0x1d ++#define RADIO_2057_VCOCAL_DELAY_AFTER_OPENLOOP 0x1e ++#define RADIO_2057_VCOCAL_DELAY_BEFORE_OPENLOOP 0x1f ++#define RADIO_2057_VCO_FORCECAPEN_FORCECAP1 0x20 ++#define RADIO_2057_VCO_FORCECAP0 0x21 ++#define RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE 0x22 ++#define RADIO_2057_RFPLL_PFD_RESET_PW 0x23 ++#define RADIO_2057_RFPLL_LOOPFILTER_R2 0x24 ++#define RADIO_2057_RFPLL_LOOPFILTER_R1 0x25 ++#define RADIO_2057_RFPLL_LOOPFILTER_C3 0x26 ++#define RADIO_2057_RFPLL_LOOPFILTER_C2 0x27 ++#define RADIO_2057_RFPLL_LOOPFILTER_C1 0x28 ++#define RADIO_2057_CP_KPD_IDAC 0x29 ++#define RADIO_2057_RFPLL_IDACS 0x2a ++#define RADIO_2057_RFPLL_MISC_EN 0x2b ++#define RADIO_2057_RFPLL_MMD0 0x2c ++#define RADIO_2057_RFPLL_MMD1 0x2d ++#define RADIO_2057_RFPLL_MISC_CAL_RESETN 0x2e ++#define RADIO_2057_JTAGXTAL_SIZE_CPBIAS_FILTRES 0x2f ++#define RADIO_2057_VCO_ALCREF_BBPLLXTAL_SIZE 0x30 ++#define RADIO_2057_VCOCAL_READCAP0 0x31 ++#define RADIO_2057_VCOCAL_READCAP1 0x32 ++#define RADIO_2057_VCOCAL_STATUS 0x33 ++#define RADIO_2057_LOGEN_PUS 0x34 ++#define RADIO_2057_LOGEN_PTAT_RESETS 0x35 ++#define RADIO_2057_VCOBUF_IDACS 0x36 ++#define RADIO_2057_VCOBUF_TUNE 0x37 ++#define RADIO_2057_CMOSBUF_TX2GQ_IDACS 0x38 ++#define RADIO_2057_CMOSBUF_TX2GI_IDACS 0x39 ++#define RADIO_2057_CMOSBUF_TX5GQ_IDACS 0x3a ++#define RADIO_2057_CMOSBUF_TX5GI_IDACS 0x3b ++#define RADIO_2057_CMOSBUF_RX2GQ_IDACS 0x3c ++#define RADIO_2057_CMOSBUF_RX2GI_IDACS 0x3d ++#define RADIO_2057_CMOSBUF_RX5GQ_IDACS 0x3e ++#define RADIO_2057_CMOSBUF_RX5GI_IDACS 0x3f ++#define RADIO_2057_LOGEN_MX2G_IDACS 0x40 ++#define RADIO_2057_LOGEN_MX2G_TUNE 0x41 ++#define RADIO_2057_LOGEN_MX5G_IDACS 0x42 ++#define RADIO_2057_LOGEN_MX5G_TUNE 0x43 ++#define RADIO_2057_LOGEN_MX5G_RCCR 0x44 ++#define RADIO_2057_LOGEN_INDBUF2G_IDAC 0x45 ++#define RADIO_2057_LOGEN_INDBUF2G_IBOOST 0x46 ++#define RADIO_2057_LOGEN_INDBUF2G_TUNE 0x47 ++#define RADIO_2057_LOGEN_INDBUF5G_IDAC 0x48 ++#define RADIO_2057_LOGEN_INDBUF5G_IBOOST 0x49 ++#define RADIO_2057_LOGEN_INDBUF5G_TUNE 0x4a ++#define RADIO_2057_CMOSBUF_TX_RCCR 0x4b ++#define RADIO_2057_CMOSBUF_RX_RCCR 0x4c ++#define RADIO_2057_LOGEN_SEL_PKDET 0x4d ++#define RADIO_2057_CMOSBUF_SHAREIQ_PTAT 0x4e ++#define RADIO_2057_RXTXBIAS_CONFIG_CORE0 0x4f ++#define RADIO_2057_TXGM_TXRF_PUS_CORE0 0x50 ++#define RADIO_2057_TXGM_IDAC_BLEED_CORE0 0x51 ++#define RADIO_2057_TXGM_GAIN_CORE0 0x56 ++#define RADIO_2057_TXGM2G_PKDET_PUS_CORE0 0x57 ++#define RADIO_2057_PAD2G_PTATS_CORE0 0x58 ++#define RADIO_2057_PAD2G_IDACS_CORE0 0x59 ++#define RADIO_2057_PAD2G_BOOST_PU_CORE0 0x5a ++#define RADIO_2057_PAD2G_CASCV_GAIN_CORE0 0x5b ++#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0 0x5c ++#define RADIO_2057_TXMIX2G_LODC_CORE0 0x5d ++#define RADIO_2057_PAD2G_TUNE_PUS_CORE0 0x5e ++#define RADIO_2057_IPA2G_GAIN_CORE0 0x5f ++#define RADIO_2057_TSSI2G_SPARE1_CORE0 0x60 ++#define RADIO_2057_TSSI2G_SPARE2_CORE0 0x61 ++#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE0 0x62 ++#define RADIO_2057_IPA2G_IMAIN_CORE0 0x63 ++#define RADIO_2057_IPA2G_CASCONV_CORE0 0x64 ++#define RADIO_2057_IPA2G_CASCOFFV_CORE0 0x65 ++#define RADIO_2057_IPA2G_BIAS_FILTER_CORE0 0x66 ++#define RADIO_2057_TX5G_PKDET_CORE0 0x69 ++#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE0 0x6a ++#define RADIO_2057_PAD5G_PTATS1_CORE0 0x6b ++#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE0 0x6c ++#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE0 0x6d ++#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE0 0x6e ++#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0 0x6f ++#define RADIO_2057_PGA_BOOST_TUNE_CORE0 0x70 ++#define RADIO_2057_PGA_GAIN_CORE0 0x71 ++#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0 0x72 ++#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0 0x73 ++#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0 0x74 ++#define RADIO_2057_IPA5G_IAUX_CORE0 0x75 ++#define RADIO_2057_IPA5G_GAIN_CORE0 0x76 ++#define RADIO_2057_TSSI5G_SPARE1_CORE0 0x77 ++#define RADIO_2057_TSSI5G_SPARE2_CORE0 0x78 ++#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE0 0x79 ++#define RADIO_2057_IPA5G_PTAT_CORE0 0x7a ++#define RADIO_2057_IPA5G_IMAIN_CORE0 0x7b ++#define RADIO_2057_IPA5G_CASCONV_CORE0 0x7c ++#define RADIO_2057_IPA5G_BIAS_FILTER_CORE0 0x7d ++#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE0 0x80 ++#define RADIO_2057_TR2G_CONFIG1_CORE0_NU 0x81 ++#define RADIO_2057_TR2G_CONFIG2_CORE0_NU 0x82 ++#define RADIO_2057_LNA5G_RFEN_CORE0 0x83 ++#define RADIO_2057_TR5G_CONFIG2_CORE0_NU 0x84 ++#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE0 0x85 ++#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0 0x86 ++#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE0 0x87 ++#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE0 0x88 ++#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE0 0x89 ++#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE0 0x8a ++#define RADIO_2057_LNA2_IAUX_PTAT_CORE0 0x8b ++#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE0 0x8c ++#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE0 0x8d ++#define RADIO_2057_RXRFBIAS_BANDSEL_CORE0 0x8e ++#define RADIO_2057_TIA_CONFIG_CORE0 0x8f ++#define RADIO_2057_TIA_IQGAIN_CORE0 0x90 ++#define RADIO_2057_TIA_IBIAS2_CORE0 0x91 ++#define RADIO_2057_TIA_IBIAS1_CORE0 0x92 ++#define RADIO_2057_TIA_SPARE_Q_CORE0 0x93 ++#define RADIO_2057_TIA_SPARE_I_CORE0 0x94 ++#define RADIO_2057_RXMIX2G_PUS_CORE0 0x95 ++#define RADIO_2057_RXMIX2G_VCMREFS_CORE0 0x96 ++#define RADIO_2057_RXMIX2G_LODC_QI_CORE0 0x97 ++#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE0 0x98 ++#define RADIO_2057_LNA2G_GAIN_CORE0 0x99 ++#define RADIO_2057_LNA2G_TUNE_CORE0 0x9a ++#define RADIO_2057_RXMIX5G_PUS_CORE0 0x9b ++#define RADIO_2057_RXMIX5G_VCMREFS_CORE0 0x9c ++#define RADIO_2057_RXMIX5G_LODC_QI_CORE0 0x9d ++#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE0 0x9e ++#define RADIO_2057_LNA5G_GAIN_CORE0 0x9f ++#define RADIO_2057_LNA5G_TUNE_CORE0 0xa0 ++#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE0 0xa1 ++#define RADIO_2057_RXBB_BIAS_MASTER_CORE0 0xa2 ++#define RADIO_2057_RXBB_VGABUF_IDACS_CORE0 0xa3 ++#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE0 0xa4 ++#define RADIO_2057_TXBUF_VINCM_CORE0 0xa5 ++#define RADIO_2057_TXBUF_IDACS_CORE0 0xa6 ++#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE0 0xa7 ++#define RADIO_2057_RXBB_CC_CORE0 0xa8 ++#define RADIO_2057_RXBB_SPARE3_CORE0 0xa9 ++#define RADIO_2057_RXBB_RCCAL_HPC_CORE0 0xaa ++#define RADIO_2057_LPF_IDACS_CORE0 0xab ++#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0 0xac ++#define RADIO_2057_TXBUF_GAIN_CORE0 0xad ++#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE0 0xae ++#define RADIO_2057_RXBUF_DEGEN_CORE0 0xaf ++#define RADIO_2057_RXBB_SPARE2_CORE0 0xb0 ++#define RADIO_2057_RXBB_SPARE1_CORE0 0xb1 ++#define RADIO_2057_RSSI_MASTER_CORE0 0xb2 ++#define RADIO_2057_W2_MASTER_CORE0 0xb3 ++#define RADIO_2057_NB_MASTER_CORE0 0xb4 ++#define RADIO_2057_W2_IDACS0_Q_CORE0 0xb5 ++#define RADIO_2057_W2_IDACS1_Q_CORE0 0xb6 ++#define RADIO_2057_W2_IDACS0_I_CORE0 0xb7 ++#define RADIO_2057_W2_IDACS1_I_CORE0 0xb8 ++#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE0 0xb9 ++#define RADIO_2057_NB_IDACS_Q_CORE0 0xba ++#define RADIO_2057_NB_IDACS_I_CORE0 0xbb ++#define RADIO_2057_BACKUP4_CORE0 0xc1 ++#define RADIO_2057_BACKUP3_CORE0 0xc2 ++#define RADIO_2057_BACKUP2_CORE0 0xc3 ++#define RADIO_2057_BACKUP1_CORE0 0xc4 ++#define RADIO_2057_SPARE16_CORE0 0xc5 ++#define RADIO_2057_SPARE15_CORE0 0xc6 ++#define RADIO_2057_SPARE14_CORE0 0xc7 ++#define RADIO_2057_SPARE13_CORE0 0xc8 ++#define RADIO_2057_SPARE12_CORE0 0xc9 ++#define RADIO_2057_SPARE11_CORE0 0xca ++#define RADIO_2057_TX2G_BIAS_RESETS_CORE0 0xcb ++#define RADIO_2057_TX5G_BIAS_RESETS_CORE0 0xcc ++#define RADIO_2057_IQTEST_SEL_PU 0xcd ++#define RADIO_2057_XTAL_CONFIG2 0xce ++#define RADIO_2057_BUFS_MISC_LPFBW_CORE0 0xcf ++#define RADIO_2057_TXLPF_RCCAL_CORE0 0xd0 ++#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0xd1 ++#define RADIO_2057_LPF_GAIN_CORE0 0xd2 ++#define RADIO_2057_DACBUF_IDACS_BW_CORE0 0xd3 ++#define RADIO_2057_RXTXBIAS_CONFIG_CORE1 0xd4 ++#define RADIO_2057_TXGM_TXRF_PUS_CORE1 0xd5 ++#define RADIO_2057_TXGM_IDAC_BLEED_CORE1 0xd6 ++#define RADIO_2057_TXGM_GAIN_CORE1 0xdb ++#define RADIO_2057_TXGM2G_PKDET_PUS_CORE1 0xdc ++#define RADIO_2057_PAD2G_PTATS_CORE1 0xdd ++#define RADIO_2057_PAD2G_IDACS_CORE1 0xde ++#define RADIO_2057_PAD2G_BOOST_PU_CORE1 0xdf ++#define RADIO_2057_PAD2G_CASCV_GAIN_CORE1 0xe0 ++#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1 0xe1 ++#define RADIO_2057_TXMIX2G_LODC_CORE1 0xe2 ++#define RADIO_2057_PAD2G_TUNE_PUS_CORE1 0xe3 ++#define RADIO_2057_IPA2G_GAIN_CORE1 0xe4 ++#define RADIO_2057_TSSI2G_SPARE1_CORE1 0xe5 ++#define RADIO_2057_TSSI2G_SPARE2_CORE1 0xe6 ++#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE1 0xe7 ++#define RADIO_2057_IPA2G_IMAIN_CORE1 0xe8 ++#define RADIO_2057_IPA2G_CASCONV_CORE1 0xe9 ++#define RADIO_2057_IPA2G_CASCOFFV_CORE1 0xea ++#define RADIO_2057_IPA2G_BIAS_FILTER_CORE1 0xeb ++#define RADIO_2057_TX5G_PKDET_CORE1 0xee ++#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE1 0xef ++#define RADIO_2057_PAD5G_PTATS1_CORE1 0xf0 ++#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE1 0xf1 ++#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE1 0xf2 ++#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE1 0xf3 ++#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1 0xf4 ++#define RADIO_2057_PGA_BOOST_TUNE_CORE1 0xf5 ++#define RADIO_2057_PGA_GAIN_CORE1 0xf6 ++#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1 0xf7 ++#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1 0xf8 ++#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1 0xf9 ++#define RADIO_2057_IPA5G_IAUX_CORE1 0xfa ++#define RADIO_2057_IPA5G_GAIN_CORE1 0xfb ++#define RADIO_2057_TSSI5G_SPARE1_CORE1 0xfc ++#define RADIO_2057_TSSI5G_SPARE2_CORE1 0xfd ++#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE1 0xfe ++#define RADIO_2057_IPA5G_PTAT_CORE1 0xff ++#define RADIO_2057_IPA5G_IMAIN_CORE1 0x100 ++#define RADIO_2057_IPA5G_CASCONV_CORE1 0x101 ++#define RADIO_2057_IPA5G_BIAS_FILTER_CORE1 0x102 ++#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE1 0x105 ++#define RADIO_2057_TR2G_CONFIG1_CORE1_NU 0x106 ++#define RADIO_2057_TR2G_CONFIG2_CORE1_NU 0x107 ++#define RADIO_2057_LNA5G_RFEN_CORE1 0x108 ++#define RADIO_2057_TR5G_CONFIG2_CORE1_NU 0x109 ++#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE1 0x10a ++#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1 0x10b ++#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE1 0x10c ++#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE1 0x10d ++#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE1 0x10e ++#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE1 0x10f ++#define RADIO_2057_LNA2_IAUX_PTAT_CORE1 0x110 ++#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE1 0x111 ++#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE1 0x112 ++#define RADIO_2057_RXRFBIAS_BANDSEL_CORE1 0x113 ++#define RADIO_2057_TIA_CONFIG_CORE1 0x114 ++#define RADIO_2057_TIA_IQGAIN_CORE1 0x115 ++#define RADIO_2057_TIA_IBIAS2_CORE1 0x116 ++#define RADIO_2057_TIA_IBIAS1_CORE1 0x117 ++#define RADIO_2057_TIA_SPARE_Q_CORE1 0x118 ++#define RADIO_2057_TIA_SPARE_I_CORE1 0x119 ++#define RADIO_2057_RXMIX2G_PUS_CORE1 0x11a ++#define RADIO_2057_RXMIX2G_VCMREFS_CORE1 0x11b ++#define RADIO_2057_RXMIX2G_LODC_QI_CORE1 0x11c ++#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE1 0x11d ++#define RADIO_2057_LNA2G_GAIN_CORE1 0x11e ++#define RADIO_2057_LNA2G_TUNE_CORE1 0x11f ++#define RADIO_2057_RXMIX5G_PUS_CORE1 0x120 ++#define RADIO_2057_RXMIX5G_VCMREFS_CORE1 0x121 ++#define RADIO_2057_RXMIX5G_LODC_QI_CORE1 0x122 ++#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE1 0x123 ++#define RADIO_2057_LNA5G_GAIN_CORE1 0x124 ++#define RADIO_2057_LNA5G_TUNE_CORE1 0x125 ++#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE1 0x126 ++#define RADIO_2057_RXBB_BIAS_MASTER_CORE1 0x127 ++#define RADIO_2057_RXBB_VGABUF_IDACS_CORE1 0x128 ++#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE1 0x129 ++#define RADIO_2057_TXBUF_VINCM_CORE1 0x12a ++#define RADIO_2057_TXBUF_IDACS_CORE1 0x12b ++#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE1 0x12c ++#define RADIO_2057_RXBB_CC_CORE1 0x12d ++#define RADIO_2057_RXBB_SPARE3_CORE1 0x12e ++#define RADIO_2057_RXBB_RCCAL_HPC_CORE1 0x12f ++#define RADIO_2057_LPF_IDACS_CORE1 0x130 ++#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1 0x131 ++#define RADIO_2057_TXBUF_GAIN_CORE1 0x132 ++#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE1 0x133 ++#define RADIO_2057_RXBUF_DEGEN_CORE1 0x134 ++#define RADIO_2057_RXBB_SPARE2_CORE1 0x135 ++#define RADIO_2057_RXBB_SPARE1_CORE1 0x136 ++#define RADIO_2057_RSSI_MASTER_CORE1 0x137 ++#define RADIO_2057_W2_MASTER_CORE1 0x138 ++#define RADIO_2057_NB_MASTER_CORE1 0x139 ++#define RADIO_2057_W2_IDACS0_Q_CORE1 0x13a ++#define RADIO_2057_W2_IDACS1_Q_CORE1 0x13b ++#define RADIO_2057_W2_IDACS0_I_CORE1 0x13c ++#define RADIO_2057_W2_IDACS1_I_CORE1 0x13d ++#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE1 0x13e ++#define RADIO_2057_NB_IDACS_Q_CORE1 0x13f ++#define RADIO_2057_NB_IDACS_I_CORE1 0x140 ++#define RADIO_2057_BACKUP4_CORE1 0x146 ++#define RADIO_2057_BACKUP3_CORE1 0x147 ++#define RADIO_2057_BACKUP2_CORE1 0x148 ++#define RADIO_2057_BACKUP1_CORE1 0x149 ++#define RADIO_2057_SPARE16_CORE1 0x14a ++#define RADIO_2057_SPARE15_CORE1 0x14b ++#define RADIO_2057_SPARE14_CORE1 0x14c ++#define RADIO_2057_SPARE13_CORE1 0x14d ++#define RADIO_2057_SPARE12_CORE1 0x14e ++#define RADIO_2057_SPARE11_CORE1 0x14f ++#define RADIO_2057_TX2G_BIAS_RESETS_CORE1 0x150 ++#define RADIO_2057_TX5G_BIAS_RESETS_CORE1 0x151 ++#define RADIO_2057_SPARE8_CORE1 0x152 ++#define RADIO_2057_SPARE7_CORE1 0x153 ++#define RADIO_2057_BUFS_MISC_LPFBW_CORE1 0x154 ++#define RADIO_2057_TXLPF_RCCAL_CORE1 0x155 ++#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156 ++#define RADIO_2057_LPF_GAIN_CORE1 0x157 ++#define RADIO_2057_DACBUF_IDACS_BW_CORE1 0x158 ++#define RADIO_2057_DACBUF_VINCM_CORE1 0x159 ++#define RADIO_2057_RCCAL_START_R1_Q1_P1 0x15a ++#define RADIO_2057_RCCAL_X1 0x15b ++#define RADIO_2057_RCCAL_TRC0 0x15c ++#define RADIO_2057_RCCAL_TRC1 0x15d ++#define RADIO_2057_RCCAL_DONE_OSCCAP 0x15e ++#define RADIO_2057_RCCAL_N0_0 0x15f ++#define RADIO_2057_RCCAL_N0_1 0x160 ++#define RADIO_2057_RCCAL_N1_0 0x161 ++#define RADIO_2057_RCCAL_N1_1 0x162 ++#define RADIO_2057_RCAL_STATUS 0x163 ++#define RADIO_2057_XTALPUOVR_PINCTRL 0x164 ++#define RADIO_2057_OVR_REG0 0x165 ++#define RADIO_2057_OVR_REG1 0x166 ++#define RADIO_2057_OVR_REG2 0x167 ++#define RADIO_2057_OVR_REG3 0x168 ++#define RADIO_2057_OVR_REG4 0x169 ++#define RADIO_2057_RCCAL_SCAP_VAL 0x16a ++#define RADIO_2057_RCCAL_BCAP_VAL 0x16b ++#define RADIO_2057_RCCAL_HPC_VAL 0x16c ++#define RADIO_2057_RCCAL_OVERRIDES 0x16d ++#define RADIO_2057_TX0_IQCAL_GAIN_BW 0x170 ++#define RADIO_2057_TX0_LOFT_FINE_I 0x171 ++#define RADIO_2057_TX0_LOFT_FINE_Q 0x172 ++#define RADIO_2057_TX0_LOFT_COARSE_I 0x173 ++#define RADIO_2057_TX0_LOFT_COARSE_Q 0x174 ++#define RADIO_2057_TX0_TX_SSI_MASTER 0x175 ++#define RADIO_2057_TX0_IQCAL_VCM_HG 0x176 ++#define RADIO_2057_TX0_IQCAL_IDAC 0x177 ++#define RADIO_2057_TX0_TSSI_VCM 0x178 ++#define RADIO_2057_TX0_TX_SSI_MUX 0x179 ++#define RADIO_2057_TX0_TSSIA 0x17a ++#define RADIO_2057_TX0_TSSIG 0x17b ++#define RADIO_2057_TX0_TSSI_MISC1 0x17c ++#define RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN 0x17d ++#define RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e ++#define RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f ++#define RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180 ++#define RADIO_2057_TX1_IQCAL_GAIN_BW 0x190 ++#define RADIO_2057_TX1_LOFT_FINE_I 0x191 ++#define RADIO_2057_TX1_LOFT_FINE_Q 0x192 ++#define RADIO_2057_TX1_LOFT_COARSE_I 0x193 ++#define RADIO_2057_TX1_LOFT_COARSE_Q 0x194 ++#define RADIO_2057_TX1_TX_SSI_MASTER 0x195 ++#define RADIO_2057_TX1_IQCAL_VCM_HG 0x196 ++#define RADIO_2057_TX1_IQCAL_IDAC 0x197 ++#define RADIO_2057_TX1_TSSI_VCM 0x198 ++#define RADIO_2057_TX1_TX_SSI_MUX 0x199 ++#define RADIO_2057_TX1_TSSIA 0x19a ++#define RADIO_2057_TX1_TSSIG 0x19b ++#define RADIO_2057_TX1_TSSI_MISC1 0x19c ++#define RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN 0x19d ++#define RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e ++#define RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f ++#define RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0 ++#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1 ++#define RADIO_2057_AFE_SET_VCM_I_CORE0 0x1a2 ++#define RADIO_2057_AFE_SET_VCM_Q_CORE0 0x1a3 ++#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE0 0x1a4 ++#define RADIO_2057_AFE_STATUS_VCM_I_CORE0 0x1a5 ++#define RADIO_2057_AFE_STATUS_VCM_Q_CORE0 0x1a6 ++#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE1 0x1a7 ++#define RADIO_2057_AFE_SET_VCM_I_CORE1 0x1a8 ++#define RADIO_2057_AFE_SET_VCM_Q_CORE1 0x1a9 ++#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE1 0x1aa ++#define RADIO_2057_AFE_STATUS_VCM_I_CORE1 0x1ab ++#define RADIO_2057_AFE_STATUS_VCM_Q_CORE1 0x1ac ++ ++#define RADIO_2057v7_DACBUF_VINCM_CORE0 0x1ad ++#define RADIO_2057v7_RCCAL_MASTER 0x1ae ++#define RADIO_2057v7_TR2G_CONFIG3_CORE0_NU 0x1af ++#define RADIO_2057v7_TR2G_CONFIG3_CORE1_NU 0x1b0 ++#define RADIO_2057v7_LOGEN_PUS1 0x1b1 ++#define RADIO_2057v7_OVR_REG5 0x1b2 ++#define RADIO_2057v7_OVR_REG6 0x1b3 ++#define RADIO_2057v7_OVR_REG7 0x1b4 ++#define RADIO_2057v7_OVR_REG8 0x1b5 ++#define RADIO_2057v7_OVR_REG9 0x1b6 ++#define RADIO_2057v7_OVR_REG10 0x1b7 ++#define RADIO_2057v7_OVR_REG11 0x1b8 ++#define RADIO_2057v7_OVR_REG12 0x1b9 ++#define RADIO_2057v7_OVR_REG13 0x1ba ++#define RADIO_2057v7_OVR_REG14 0x1bb ++#define RADIO_2057v7_OVR_REG15 0x1bc ++#define RADIO_2057v7_OVR_REG16 0x1bd ++#define RADIO_2057v7_OVR_REG1 0x1be ++#define RADIO_2057v7_OVR_REG18 0x1bf ++#define RADIO_2057v7_OVR_REG19 0x1c0 ++#define RADIO_2057v7_OVR_REG20 0x1c1 ++#define RADIO_2057v7_OVR_REG21 0x1c2 ++#define RADIO_2057v7_OVR_REG2 0x1c3 ++#define RADIO_2057v7_OVR_REG23 0x1c4 ++#define RADIO_2057v7_OVR_REG24 0x1c5 ++#define RADIO_2057v7_OVR_REG25 0x1c6 ++#define RADIO_2057v7_OVR_REG26 0x1c7 ++#define RADIO_2057v7_OVR_REG27 0x1c8 ++#define RADIO_2057v7_OVR_REG28 0x1c9 ++#define RADIO_2057v7_IQTEST_SEL_PU2 0x1ca ++ ++#define RADIO_2057_VCM_MASK 0x7 ++ ++#endif /* _BRCM_PHY_RADIO_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h.orig 2011-11-09 13:46:58.277800233 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h 2011-11-09 13:47:17.035565729 -0500 +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++#define NPHY_TBL_ID_GAIN1 0 ++#define NPHY_TBL_ID_GAIN2 1 ++#define NPHY_TBL_ID_GAINBITS1 2 ++#define NPHY_TBL_ID_GAINBITS2 3 ++#define NPHY_TBL_ID_GAINLIMIT 4 ++#define NPHY_TBL_ID_WRSSIGainLimit 5 ++#define NPHY_TBL_ID_RFSEQ 7 ++#define NPHY_TBL_ID_AFECTRL 8 ++#define NPHY_TBL_ID_ANTSWCTRLLUT 9 ++#define NPHY_TBL_ID_IQLOCAL 15 ++#define NPHY_TBL_ID_NOISEVAR 16 ++#define NPHY_TBL_ID_SAMPLEPLAY 17 ++#define NPHY_TBL_ID_CORE1TXPWRCTL 26 ++#define NPHY_TBL_ID_CORE2TXPWRCTL 27 ++#define NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL 30 ++ ++#define NPHY_TBL_ID_EPSILONTBL0 31 ++#define NPHY_TBL_ID_SCALARTBL0 32 ++#define NPHY_TBL_ID_EPSILONTBL1 33 ++#define NPHY_TBL_ID_SCALARTBL1 34 ++ ++#define NPHY_TO_BPHY_OFF 0xc00 ++ ++#define NPHY_BandControl_currentBand 0x0001 ++#define RFCC_CHIP0_PU 0x0400 ++#define RFCC_POR_FORCE 0x0040 ++#define RFCC_OE_POR_FORCE 0x0080 ++#define NPHY_RfctrlIntc_override_OFF 0 ++#define NPHY_RfctrlIntc_override_TRSW 1 ++#define NPHY_RfctrlIntc_override_PA 2 ++#define NPHY_RfctrlIntc_override_EXT_LNA_PU 3 ++#define NPHY_RfctrlIntc_override_EXT_LNA_GAIN 4 ++#define RIFS_ENABLE 0x80 ++#define BPHY_BAND_SEL_UP20 0x10 ++#define NPHY_MLenable 0x02 ++ ++#define NPHY_RfseqMode_CoreActv_override 0x0001 ++#define NPHY_RfseqMode_Trigger_override 0x0002 ++#define NPHY_RfseqCoreActv_TxRxChain0 (0x11) ++#define NPHY_RfseqCoreActv_TxRxChain1 (0x22) ++ ++#define NPHY_RfseqTrigger_rx2tx 0x0001 ++#define NPHY_RfseqTrigger_tx2rx 0x0002 ++#define NPHY_RfseqTrigger_updategainh 0x0004 ++#define NPHY_RfseqTrigger_updategainl 0x0008 ++#define NPHY_RfseqTrigger_updategainu 0x0010 ++#define NPHY_RfseqTrigger_reset2rx 0x0020 ++#define NPHY_RfseqStatus_rx2tx 0x0001 ++#define NPHY_RfseqStatus_tx2rx 0x0002 ++#define NPHY_RfseqStatus_updategainh 0x0004 ++#define NPHY_RfseqStatus_updategainl 0x0008 ++#define NPHY_RfseqStatus_updategainu 0x0010 ++#define NPHY_RfseqStatus_reset2rx 0x0020 ++#define NPHY_ClassifierCtrl_cck_en 0x1 ++#define NPHY_ClassifierCtrl_ofdm_en 0x2 ++#define NPHY_ClassifierCtrl_waited_en 0x4 ++#define NPHY_IQFlip_ADC1 0x0001 ++#define NPHY_IQFlip_ADC2 0x0010 ++#define NPHY_sampleCmd_STOP 0x0002 ++ ++#define RX_GF_OR_MM 0x0004 ++#define RX_GF_MM_AUTO 0x0100 ++ ++#define NPHY_iqloCalCmdGctl_IQLO_CAL_EN 0x8000 ++ ++#define NPHY_IqestCmd_iqstart 0x1 ++#define NPHY_IqestCmd_iqMode 0x2 ++ ++#define NPHY_TxPwrCtrlCmd_pwrIndex_init 0x40 ++#define NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 0x19 ++ ++#define PRIM_SEL_UP20 0x8000 ++ ++#define NPHY_RFSEQ_RX2TX 0x0 ++#define NPHY_RFSEQ_TX2RX 0x1 ++#define NPHY_RFSEQ_RESET2RX 0x2 ++#define NPHY_RFSEQ_UPDATEGAINH 0x3 ++#define NPHY_RFSEQ_UPDATEGAINL 0x4 ++#define NPHY_RFSEQ_UPDATEGAINU 0x5 ++ ++#define NPHY_RFSEQ_CMD_NOP 0x0 ++#define NPHY_RFSEQ_CMD_RXG_FBW 0x1 ++#define NPHY_RFSEQ_CMD_TR_SWITCH 0x2 ++#define NPHY_RFSEQ_CMD_EXT_PA 0x3 ++#define NPHY_RFSEQ_CMD_RXPD_TXPD 0x4 ++#define NPHY_RFSEQ_CMD_TX_GAIN 0x5 ++#define NPHY_RFSEQ_CMD_RX_GAIN 0x6 ++#define NPHY_RFSEQ_CMD_SET_HPF_BW 0x7 ++#define NPHY_RFSEQ_CMD_CLR_HIQ_DIS 0x8 ++#define NPHY_RFSEQ_CMD_END 0xf ++ ++#define NPHY_REV3_RFSEQ_CMD_NOP 0x0 ++#define NPHY_REV3_RFSEQ_CMD_RXG_FBW 0x1 ++#define NPHY_REV3_RFSEQ_CMD_TR_SWITCH 0x2 ++#define NPHY_REV3_RFSEQ_CMD_INT_PA_PU 0x3 ++#define NPHY_REV3_RFSEQ_CMD_EXT_PA 0x4 ++#define NPHY_REV3_RFSEQ_CMD_RXPD_TXPD 0x5 ++#define NPHY_REV3_RFSEQ_CMD_TX_GAIN 0x6 ++#define NPHY_REV3_RFSEQ_CMD_RX_GAIN 0x7 ++#define NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS 0x8 ++#define NPHY_REV3_RFSEQ_CMD_SET_HPF_H_HPC 0x9 ++#define NPHY_REV3_RFSEQ_CMD_SET_LPF_H_HPC 0xa ++#define NPHY_REV3_RFSEQ_CMD_SET_HPF_M_HPC 0xb ++#define NPHY_REV3_RFSEQ_CMD_SET_LPF_M_HPC 0xc ++#define NPHY_REV3_RFSEQ_CMD_SET_HPF_L_HPC 0xd ++#define NPHY_REV3_RFSEQ_CMD_SET_LPF_L_HPC 0xe ++#define NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS 0xf ++#define NPHY_REV3_RFSEQ_CMD_END 0x1f ++ ++#define NPHY_RSSI_SEL_W1 0x0 ++#define NPHY_RSSI_SEL_W2 0x1 ++#define NPHY_RSSI_SEL_NB 0x2 ++#define NPHY_RSSI_SEL_IQ 0x3 ++#define NPHY_RSSI_SEL_TSSI_2G 0x4 ++#define NPHY_RSSI_SEL_TSSI_5G 0x5 ++#define NPHY_RSSI_SEL_TBD 0x6 ++ ++#define NPHY_RAIL_I 0x0 ++#define NPHY_RAIL_Q 0x1 ++ ++#define NPHY_FORCESIG_DECODEGATEDCLKS 0x8 ++ ++#define NPHY_REV7_RfctrlOverride_cmd_rxrf_pu 0x0 ++#define NPHY_REV7_RfctrlOverride_cmd_rx_pu 0x1 ++#define NPHY_REV7_RfctrlOverride_cmd_tx_pu 0x2 ++#define NPHY_REV7_RfctrlOverride_cmd_rxgain 0x3 ++#define NPHY_REV7_RfctrlOverride_cmd_txgain 0x4 ++ ++#define NPHY_REV7_RXGAINCODE_RFMXGAIN_MASK 0x000ff ++#define NPHY_REV7_RXGAINCODE_LPFGAIN_MASK 0x0ff00 ++#define NPHY_REV7_RXGAINCODE_DVGAGAIN_MASK 0xf0000 ++ ++#define NPHY_REV7_TXGAINCODE_TGAIN_MASK 0x7fff ++#define NPHY_REV7_TXGAINCODE_LPFGAIN_MASK 0x8000 ++#define NPHY_REV7_TXGAINCODE_BIQ0GAIN_SHIFT 14 ++ ++#define NPHY_REV7_RFCTRLOVERRIDE_ID0 0x0 ++#define NPHY_REV7_RFCTRLOVERRIDE_ID1 0x1 ++#define NPHY_REV7_RFCTRLOVERRIDE_ID2 0x2 ++ ++#define NPHY_IqestIqAccLo(core) ((core == 0) ? 0x12c : 0x134) ++ ++#define NPHY_IqestIqAccHi(core) ((core == 0) ? 0x12d : 0x135) ++ ++#define NPHY_IqestipwrAccLo(core) ((core == 0) ? 0x12e : 0x136) ++ ++#define NPHY_IqestipwrAccHi(core) ((core == 0) ? 0x12f : 0x137) ++ ++#define NPHY_IqestqpwrAccLo(core) ((core == 0) ? 0x130 : 0x138) ++ ++#define NPHY_IqestqpwrAccHi(core) ((core == 0) ? 0x131 : 0x139) +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c.orig 2011-11-09 13:46:58.278800221 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c 2011-11-09 13:47:17.036565717 -0500 +@@ -0,0 +1,3250 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include "phytbl_lcn.h" ++ ++static const u32 dot11lcn_gain_tbl_rev0[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000004, ++ 0x00000000, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000d, ++ 0x0000004d, ++ 0x0000008d, ++ 0x0000000d, ++ 0x0000004d, ++ 0x0000008d, ++ 0x000000cd, ++ 0x0000004f, ++ 0x0000008f, ++ 0x000000cf, ++ 0x000000d3, ++ 0x00000113, ++ 0x00000513, ++ 0x00000913, ++ 0x00000953, ++ 0x00000d53, ++ 0x00001153, ++ 0x00001193, ++ 0x00005193, ++ 0x00009193, ++ 0x0000d193, ++ 0x00011193, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000004, ++ 0x00000000, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000d, ++ 0x0000004d, ++ 0x0000008d, ++ 0x0000000d, ++ 0x0000004d, ++ 0x0000008d, ++ 0x000000cd, ++ 0x0000004f, ++ 0x0000008f, ++ 0x000000cf, ++ 0x000000d3, ++ 0x00000113, ++ 0x00000513, ++ 0x00000913, ++ 0x00000953, ++ 0x00000d53, ++ 0x00001153, ++ 0x00005153, ++ 0x00009153, ++ 0x0000d153, ++ 0x00011153, ++ 0x00015153, ++ 0x00019153, ++ 0x0001d153, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 dot11lcn_gain_tbl_rev1[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000008, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000D, ++ 0x00000011, ++ 0x00000051, ++ 0x00000091, ++ 0x00000011, ++ 0x00000051, ++ 0x00000091, ++ 0x000000d1, ++ 0x00000053, ++ 0x00000093, ++ 0x000000d3, ++ 0x000000d7, ++ 0x00000117, ++ 0x00000517, ++ 0x00000917, ++ 0x00000957, ++ 0x00000d57, ++ 0x00001157, ++ 0x00001197, ++ 0x00005197, ++ 0x00009197, ++ 0x0000d197, ++ 0x00011197, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000008, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000D, ++ 0x00000011, ++ 0x00000051, ++ 0x00000091, ++ 0x00000011, ++ 0x00000051, ++ 0x00000091, ++ 0x000000d1, ++ 0x00000053, ++ 0x00000093, ++ 0x000000d3, ++ 0x000000d7, ++ 0x00000117, ++ 0x00000517, ++ 0x00000917, ++ 0x00000957, ++ 0x00000d57, ++ 0x00001157, ++ 0x00005157, ++ 0x00009157, ++ 0x0000d157, ++ 0x00011157, ++ 0x00015157, ++ 0x00019157, ++ 0x0001d157, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = { ++ 0x0401, ++ 0x0402, ++ 0x0403, ++ 0x0404, ++ 0x0405, ++ 0x0406, ++ 0x0407, ++ 0x0408, ++ 0x0409, ++ 0x040a, ++ 0x058b, ++ 0x058c, ++ 0x058d, ++ 0x058e, ++ 0x058f, ++ 0x0090, ++ 0x0091, ++ 0x0092, ++ 0x0193, ++ 0x0194, ++ 0x0195, ++ 0x0196, ++ 0x0197, ++ 0x0198, ++ 0x0199, ++ 0x019a, ++ 0x019b, ++ 0x019c, ++ 0x019d, ++ 0x019e, ++ 0x019f, ++ 0x01a0, ++ 0x01a1, ++ 0x01a2, ++ 0x01a3, ++ 0x01a4, ++ 0x01a5, ++ 0x0000, ++}; ++ ++static const u32 dot11lcn_gain_idx_tbl_rev0[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x10000000, ++ 0x00000000, ++ 0x20000000, ++ 0x00000000, ++ 0x30000000, ++ 0x00000000, ++ 0x40000000, ++ 0x00000000, ++ 0x50000000, ++ 0x00000000, ++ 0x60000000, ++ 0x00000000, ++ 0x70000000, ++ 0x00000000, ++ 0x80000000, ++ 0x00000000, ++ 0x90000000, ++ 0x00000008, ++ 0xa0000000, ++ 0x00000008, ++ 0xb0000000, ++ 0x00000008, ++ 0xc0000000, ++ 0x00000008, ++ 0xd0000000, ++ 0x00000008, ++ 0xe0000000, ++ 0x00000008, ++ 0xf0000000, ++ 0x00000008, ++ 0x00000000, ++ 0x00000009, ++ 0x10000000, ++ 0x00000009, ++ 0x20000000, ++ 0x00000019, ++ 0x30000000, ++ 0x00000019, ++ 0x40000000, ++ 0x00000019, ++ 0x50000000, ++ 0x00000019, ++ 0x60000000, ++ 0x00000019, ++ 0x70000000, ++ 0x00000019, ++ 0x80000000, ++ 0x00000019, ++ 0x90000000, ++ 0x00000019, ++ 0xa0000000, ++ 0x00000019, ++ 0xb0000000, ++ 0x00000019, ++ 0xc0000000, ++ 0x00000019, ++ 0xd0000000, ++ 0x00000019, ++ 0xe0000000, ++ 0x00000019, ++ 0xf0000000, ++ 0x00000019, ++ 0x00000000, ++ 0x0000001a, ++ 0x10000000, ++ 0x0000001a, ++ 0x20000000, ++ 0x0000001a, ++ 0x30000000, ++ 0x0000001a, ++ 0x40000000, ++ 0x0000001a, ++ 0x50000000, ++ 0x00000002, ++ 0x60000000, ++ 0x00000002, ++ 0x70000000, ++ 0x00000002, ++ 0x80000000, ++ 0x00000002, ++ 0x90000000, ++ 0x00000002, ++ 0xa0000000, ++ 0x00000002, ++ 0xb0000000, ++ 0x00000002, ++ 0xc0000000, ++ 0x0000000a, ++ 0xd0000000, ++ 0x0000000a, ++ 0xe0000000, ++ 0x0000000a, ++ 0xf0000000, ++ 0x0000000a, ++ 0x00000000, ++ 0x0000000b, ++ 0x10000000, ++ 0x0000000b, ++ 0x20000000, ++ 0x0000000b, ++ 0x30000000, ++ 0x0000000b, ++ 0x40000000, ++ 0x0000000b, ++ 0x50000000, ++ 0x0000001b, ++ 0x60000000, ++ 0x0000001b, ++ 0x70000000, ++ 0x0000001b, ++ 0x80000000, ++ 0x0000001b, ++ 0x90000000, ++ 0x0000001b, ++ 0xa0000000, ++ 0x0000001b, ++ 0xb0000000, ++ 0x0000001b, ++ 0xc0000000, ++ 0x0000001b, ++ 0xd0000000, ++ 0x0000001b, ++ 0xe0000000, ++ 0x0000001b, ++ 0xf0000000, ++ 0x0000001b, ++ 0x00000000, ++ 0x0000001c, ++ 0x10000000, ++ 0x0000001c, ++ 0x20000000, ++ 0x0000001c, ++ 0x30000000, ++ 0x0000001c, ++ 0x40000000, ++ 0x0000001c, ++ 0x50000000, ++ 0x0000001c, ++ 0x60000000, ++ 0x0000001c, ++ 0x70000000, ++ 0x0000001c, ++ 0x80000000, ++ 0x0000001c, ++ 0x90000000, ++ 0x0000001c, ++}; ++ ++static const u16 dot11lcn_aux_gain_idx_tbl_2G[] = { ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0001, ++ 0x0080, ++ 0x0081, ++ 0x0100, ++ 0x0101, ++ 0x0180, ++ 0x0181, ++ 0x0182, ++ 0x0183, ++ 0x0184, ++ 0x0185, ++ 0x0186, ++ 0x0187, ++ 0x0188, ++ 0x0285, ++ 0x0289, ++ 0x028a, ++ 0x028b, ++ 0x028c, ++ 0x028d, ++ 0x028e, ++ 0x028f, ++ 0x0290, ++ 0x0291, ++ 0x0292, ++ 0x0293, ++ 0x0294, ++ 0x0295, ++ 0x0296, ++ 0x0297, ++ 0x0298, ++ 0x0299, ++ 0x029a, ++ 0x0000 ++}; ++ ++static const u8 dot11lcn_gain_val_tbl_2G[] = { ++ 0xfc, ++ 0x02, ++ 0x08, ++ 0x0e, ++ 0x13, ++ 0x1b, ++ 0xfc, ++ 0x02, ++ 0x08, ++ 0x0e, ++ 0x13, ++ 0x1b, ++ 0xfc, ++ 0x00, ++ 0x0c, ++ 0x03, ++ 0xeb, ++ 0xfe, ++ 0x07, ++ 0x0b, ++ 0x0f, ++ 0xfb, ++ 0xfe, ++ 0x01, ++ 0x05, ++ 0x08, ++ 0x0b, ++ 0x0e, ++ 0x11, ++ 0x14, ++ 0x17, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x15, ++ 0x18, ++ 0x1b, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00 ++}; ++ ++static const u32 dot11lcn_gain_idx_tbl_2G[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x10000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000008, ++ 0x10000000, ++ 0x00000008, ++ 0x00000000, ++ 0x00000010, ++ 0x10000000, ++ 0x00000010, ++ 0x00000000, ++ 0x00000018, ++ 0x10000000, ++ 0x00000018, ++ 0x20000000, ++ 0x00000018, ++ 0x30000000, ++ 0x00000018, ++ 0x40000000, ++ 0x00000018, ++ 0x50000000, ++ 0x00000018, ++ 0x60000000, ++ 0x00000018, ++ 0x70000000, ++ 0x00000018, ++ 0x80000000, ++ 0x00000018, ++ 0x50000000, ++ 0x00000028, ++ 0x90000000, ++ 0x00000028, ++ 0xa0000000, ++ 0x00000028, ++ 0xb0000000, ++ 0x00000028, ++ 0xc0000000, ++ 0x00000028, ++ 0xd0000000, ++ 0x00000028, ++ 0xe0000000, ++ 0x00000028, ++ 0xf0000000, ++ 0x00000028, ++ 0x00000000, ++ 0x00000029, ++ 0x10000000, ++ 0x00000029, ++ 0x20000000, ++ 0x00000029, ++ 0x30000000, ++ 0x00000029, ++ 0x40000000, ++ 0x00000029, ++ 0x50000000, ++ 0x00000029, ++ 0x60000000, ++ 0x00000029, ++ 0x70000000, ++ 0x00000029, ++ 0x80000000, ++ 0x00000029, ++ 0x90000000, ++ 0x00000029, ++ 0xa0000000, ++ 0x00000029, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x10000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000008, ++ 0x10000000, ++ 0x00000008, ++ 0x00000000, ++ 0x00000010, ++ 0x10000000, ++ 0x00000010, ++ 0x00000000, ++ 0x00000018, ++ 0x10000000, ++ 0x00000018, ++ 0x20000000, ++ 0x00000018, ++ 0x30000000, ++ 0x00000018, ++ 0x40000000, ++ 0x00000018, ++ 0x50000000, ++ 0x00000018, ++ 0x60000000, ++ 0x00000018, ++ 0x70000000, ++ 0x00000018, ++ 0x80000000, ++ 0x00000018, ++ 0x50000000, ++ 0x00000028, ++ 0x90000000, ++ 0x00000028, ++ 0xa0000000, ++ 0x00000028, ++ 0xb0000000, ++ 0x00000028, ++ 0xc0000000, ++ 0x00000028, ++ 0xd0000000, ++ 0x00000028, ++ 0xe0000000, ++ 0x00000028, ++ 0xf0000000, ++ 0x00000028, ++ 0x00000000, ++ 0x00000029, ++ 0x10000000, ++ 0x00000029, ++ 0x20000000, ++ 0x00000029, ++ 0x30000000, ++ 0x00000029, ++ 0x40000000, ++ 0x00000029, ++ 0x50000000, ++ 0x00000029, ++ 0x60000000, ++ 0x00000029, ++ 0x70000000, ++ 0x00000029, ++ 0x80000000, ++ 0x00000029, ++ 0x90000000, ++ 0x00000029, ++ 0xa0000000, ++ 0x00000029, ++ 0xb0000000, ++ 0x00000029, ++ 0xc0000000, ++ 0x00000029, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++static const u32 dot11lcn_gain_tbl_2G[] = { ++ 0x00000000, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000d, ++ 0x0000004d, ++ 0x0000008d, ++ 0x00000049, ++ 0x00000089, ++ 0x000000c9, ++ 0x0000004b, ++ 0x0000008b, ++ 0x000000cb, ++ 0x000000cf, ++ 0x0000010f, ++ 0x0000050f, ++ 0x0000090f, ++ 0x0000094f, ++ 0x00000d4f, ++ 0x0000114f, ++ 0x0000118f, ++ 0x0000518f, ++ 0x0000918f, ++ 0x0000d18f, ++ 0x0001118f, ++ 0x0001518f, ++ 0x0001918f, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++static const u32 dot11lcn_gain_tbl_extlna_2G[] = { ++ 0x00000000, ++ 0x00000004, ++ 0x00000008, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000d, ++ 0x00000003, ++ 0x00000007, ++ 0x0000000b, ++ 0x0000000f, ++ 0x0000004f, ++ 0x0000008f, ++ 0x000000cf, ++ 0x0000010f, ++ 0x0000014f, ++ 0x0000018f, ++ 0x0000058f, ++ 0x0000098f, ++ 0x00000d8f, ++ 0x00008000, ++ 0x00008004, ++ 0x00008008, ++ 0x00008001, ++ 0x00008005, ++ 0x00008009, ++ 0x0000800d, ++ 0x00008003, ++ 0x00008007, ++ 0x0000800b, ++ 0x0000800f, ++ 0x0000804f, ++ 0x0000808f, ++ 0x000080cf, ++ 0x0000810f, ++ 0x0000814f, ++ 0x0000818f, ++ 0x0000858f, ++ 0x0000898f, ++ 0x00008d8f, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++static const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = { ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0400, ++ 0x0401, ++ 0x0402, ++ 0x0403, ++ 0x0404, ++ 0x0483, ++ 0x0484, ++ 0x0485, ++ 0x0486, ++ 0x0583, ++ 0x0584, ++ 0x0585, ++ 0x0587, ++ 0x0588, ++ 0x0589, ++ 0x058a, ++ 0x0687, ++ 0x0688, ++ 0x0689, ++ 0x068a, ++ 0x068b, ++ 0x068c, ++ 0x068d, ++ 0x068e, ++ 0x068f, ++ 0x0690, ++ 0x0691, ++ 0x0692, ++ 0x0693, ++ 0x0000 ++}; ++ ++static const u8 dot11lcn_gain_val_tbl_extlna_2G[] = { ++ 0xfc, ++ 0x02, ++ 0x08, ++ 0x0e, ++ 0x13, ++ 0x1b, ++ 0xfc, ++ 0x02, ++ 0x08, ++ 0x0e, ++ 0x13, ++ 0x1b, ++ 0xfc, ++ 0x00, ++ 0x0f, ++ 0x03, ++ 0xeb, ++ 0xfe, ++ 0x07, ++ 0x0b, ++ 0x0f, ++ 0xfb, ++ 0xfe, ++ 0x01, ++ 0x05, ++ 0x08, ++ 0x0b, ++ 0x0e, ++ 0x11, ++ 0x14, ++ 0x17, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x15, ++ 0x18, ++ 0x1b, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00 ++}; ++ ++static const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = { ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x00000000, ++ 0x00000040, ++ 0x10000000, ++ 0x00000040, ++ 0x20000000, ++ 0x00000040, ++ 0x30000000, ++ 0x00000040, ++ 0x40000000, ++ 0x00000040, ++ 0x30000000, ++ 0x00000048, ++ 0x40000000, ++ 0x00000048, ++ 0x50000000, ++ 0x00000048, ++ 0x60000000, ++ 0x00000048, ++ 0x30000000, ++ 0x00000058, ++ 0x40000000, ++ 0x00000058, ++ 0x50000000, ++ 0x00000058, ++ 0x70000000, ++ 0x00000058, ++ 0x80000000, ++ 0x00000058, ++ 0x90000000, ++ 0x00000058, ++ 0xa0000000, ++ 0x00000058, ++ 0x70000000, ++ 0x00000068, ++ 0x80000000, ++ 0x00000068, ++ 0x90000000, ++ 0x00000068, ++ 0xa0000000, ++ 0x00000068, ++ 0xb0000000, ++ 0x00000068, ++ 0xc0000000, ++ 0x00000068, ++ 0xd0000000, ++ 0x00000068, ++ 0xe0000000, ++ 0x00000068, ++ 0xf0000000, ++ 0x00000068, ++ 0x00000000, ++ 0x00000069, ++ 0x10000000, ++ 0x00000069, ++ 0x20000000, ++ 0x00000069, ++ 0x30000000, ++ 0x00000069, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x40000000, ++ 0x00000041, ++ 0x50000000, ++ 0x00000041, ++ 0x60000000, ++ 0x00000041, ++ 0x70000000, ++ 0x00000041, ++ 0x80000000, ++ 0x00000041, ++ 0x70000000, ++ 0x00000049, ++ 0x80000000, ++ 0x00000049, ++ 0x90000000, ++ 0x00000049, ++ 0xa0000000, ++ 0x00000049, ++ 0x70000000, ++ 0x00000059, ++ 0x80000000, ++ 0x00000059, ++ 0x90000000, ++ 0x00000059, ++ 0xb0000000, ++ 0x00000059, ++ 0xc0000000, ++ 0x00000059, ++ 0xd0000000, ++ 0x00000059, ++ 0xe0000000, ++ 0x00000059, ++ 0xb0000000, ++ 0x00000069, ++ 0xc0000000, ++ 0x00000069, ++ 0xd0000000, ++ 0x00000069, ++ 0xe0000000, ++ 0x00000069, ++ 0xf0000000, ++ 0x00000069, ++ 0x00000000, ++ 0x0000006a, ++ 0x10000000, ++ 0x0000006a, ++ 0x20000000, ++ 0x0000006a, ++ 0x30000000, ++ 0x0000006a, ++ 0x40000000, ++ 0x0000006a, ++ 0x50000000, ++ 0x0000006a, ++ 0x60000000, ++ 0x0000006a, ++ 0x70000000, ++ 0x0000006a, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++static const u32 dot11lcn_aux_gain_idx_tbl_5G[] = { ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0001, ++ 0x0002, ++ 0x0003, ++ 0x0004, ++ 0x0083, ++ 0x0084, ++ 0x0085, ++ 0x0086, ++ 0x0087, ++ 0x0186, ++ 0x0187, ++ 0x0188, ++ 0x0189, ++ 0x018a, ++ 0x018b, ++ 0x018c, ++ 0x018d, ++ 0x018e, ++ 0x018f, ++ 0x0190, ++ 0x0191, ++ 0x0192, ++ 0x0193, ++ 0x0194, ++ 0x0195, ++ 0x0196, ++ 0x0197, ++ 0x0198, ++ 0x0199, ++ 0x019a, ++ 0x019b, ++ 0x019c, ++ 0x019d, ++ 0x0000 ++}; ++ ++static const u32 dot11lcn_gain_val_tbl_5G[] = { ++ 0xf7, ++ 0xfd, ++ 0x00, ++ 0x04, ++ 0x04, ++ 0x04, ++ 0xf7, ++ 0xfd, ++ 0x00, ++ 0x04, ++ 0x04, ++ 0x04, ++ 0xf6, ++ 0x00, ++ 0x0c, ++ 0x03, ++ 0xeb, ++ 0xfe, ++ 0x06, ++ 0x0a, ++ 0x10, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x15, ++ 0x18, ++ 0x1b, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x15, ++ 0x18, ++ 0x1b, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00 ++}; ++ ++static const u32 dot11lcn_gain_idx_tbl_5G[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x10000000, ++ 0x00000000, ++ 0x20000000, ++ 0x00000000, ++ 0x30000000, ++ 0x00000000, ++ 0x40000000, ++ 0x00000000, ++ 0x30000000, ++ 0x00000008, ++ 0x40000000, ++ 0x00000008, ++ 0x50000000, ++ 0x00000008, ++ 0x60000000, ++ 0x00000008, ++ 0x70000000, ++ 0x00000008, ++ 0x60000000, ++ 0x00000018, ++ 0x70000000, ++ 0x00000018, ++ 0x80000000, ++ 0x00000018, ++ 0x90000000, ++ 0x00000018, ++ 0xa0000000, ++ 0x00000018, ++ 0xb0000000, ++ 0x00000018, ++ 0xc0000000, ++ 0x00000018, ++ 0xd0000000, ++ 0x00000018, ++ 0xe0000000, ++ 0x00000018, ++ 0xf0000000, ++ 0x00000018, ++ 0x00000000, ++ 0x00000019, ++ 0x10000000, ++ 0x00000019, ++ 0x20000000, ++ 0x00000019, ++ 0x30000000, ++ 0x00000019, ++ 0x40000000, ++ 0x00000019, ++ 0x50000000, ++ 0x00000019, ++ 0x60000000, ++ 0x00000019, ++ 0x70000000, ++ 0x00000019, ++ 0x80000000, ++ 0x00000019, ++ 0x90000000, ++ 0x00000019, ++ 0xa0000000, ++ 0x00000019, ++ 0xb0000000, ++ 0x00000019, ++ 0xc0000000, ++ 0x00000019, ++ 0xd0000000, ++ 0x00000019, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++static const u32 dot11lcn_gain_tbl_5G[] = { ++ 0x00000000, ++ 0x00000040, ++ 0x00000080, ++ 0x00000001, ++ 0x00000005, ++ 0x00000009, ++ 0x0000000d, ++ 0x00000011, ++ 0x00000015, ++ 0x00000055, ++ 0x00000095, ++ 0x00000017, ++ 0x0000001b, ++ 0x0000005b, ++ 0x0000009b, ++ 0x000000db, ++ 0x0000011b, ++ 0x0000015b, ++ 0x0000019b, ++ 0x0000059b, ++ 0x0000099b, ++ 0x00000d9b, ++ 0x0000119b, ++ 0x0000519b, ++ 0x0000919b, ++ 0x0000d19b, ++ 0x0001119b, ++ 0x0001519b, ++ 0x0001919b, ++ 0x0001d19b, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000 ++}; ++ ++const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[] = { ++ {&dot11lcn_gain_tbl_rev0, ++ sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, ++ 0, 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} ++ , ++}; ++ ++static const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = { ++ {&dot11lcn_gain_tbl_rev1, ++ sizeof(dot11lcn_gain_tbl_rev1) / sizeof(dot11lcn_gain_tbl_rev1[0]), 18, ++ 0, 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} ++ , ++}; ++ ++const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[] = { ++ {&dot11lcn_gain_tbl_2G, ++ sizeof(dot11lcn_gain_tbl_2G) / sizeof(dot11lcn_gain_tbl_2G[0]), 18, 0, ++ 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_2G, ++ sizeof(dot11lcn_aux_gain_idx_tbl_2G) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_2G[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_2G, ++ sizeof(dot11lcn_gain_idx_tbl_2G) / sizeof(dot11lcn_gain_idx_tbl_2G[0]), ++ 13, 0, 32} ++ , ++ {&dot11lcn_gain_val_tbl_2G, ++ sizeof(dot11lcn_gain_val_tbl_2G) / sizeof(dot11lcn_gain_val_tbl_2G[0]), ++ 17, 0, 8} ++}; ++ ++const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[] = { ++ {&dot11lcn_gain_tbl_5G, ++ sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, ++ 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_5G, ++ sizeof(dot11lcn_aux_gain_idx_tbl_5G) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_5G, ++ sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), ++ 13, 0, 32} ++ , ++ {&dot11lcn_gain_val_tbl_5G, ++ sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), ++ 17, 0, 8} ++}; ++ ++const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[] = { ++ {&dot11lcn_gain_tbl_extlna_2G, ++ sizeof(dot11lcn_gain_tbl_extlna_2G) / ++ sizeof(dot11lcn_gain_tbl_extlna_2G[0]), 18, 0, 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_extlna_2G, ++ sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_extlna_2G, ++ sizeof(dot11lcn_gain_idx_tbl_extlna_2G) / ++ sizeof(dot11lcn_gain_idx_tbl_extlna_2G[0]), 13, 0, 32} ++ , ++ {&dot11lcn_gain_val_tbl_extlna_2G, ++ sizeof(dot11lcn_gain_val_tbl_extlna_2G) / ++ sizeof(dot11lcn_gain_val_tbl_extlna_2G[0]), 17, 0, 8} ++}; ++ ++const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[] = { ++ {&dot11lcn_gain_tbl_5G, ++ sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, ++ 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_5G, ++ sizeof(dot11lcn_aux_gain_idx_tbl_5G) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} ++ , ++ {&dot11lcn_gain_idx_tbl_5G, ++ sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), ++ 13, 0, 32} ++ , ++ {&dot11lcn_gain_val_tbl_5G, ++ sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), ++ 17, 0, 8} ++}; ++ ++const u32 dot11lcnphytbl_rx_gain_info_sz_rev0 = ++ sizeof(dot11lcnphytbl_rx_gain_info_rev0) / ++ sizeof(dot11lcnphytbl_rx_gain_info_rev0[0]); ++ ++const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz = ++ sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2) / ++ sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2[0]); ++ ++const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz = ++ sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2) / ++ sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2[0]); ++ ++static const u16 dot11lcn_min_sig_sq_tbl_rev0[] = { ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++ 0x014d, ++}; ++ ++static const u16 dot11lcn_noise_scale_tbl_rev0[] = { ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = { ++ 0x000141f8, ++ 0x000021f8, ++ 0x000021fb, ++ 0x000041fb, ++ 0x0001fe4b, ++ 0x0000217b, ++ 0x00002133, ++ 0x000040eb, ++ 0x0001fea3, ++ 0x0000024b, ++}; ++ ++static const u32 dot11lcn_ps_ctrl_tbl_rev0[] = { ++ 0x00100001, ++ 0x00200010, ++ 0x00300001, ++ 0x00400010, ++ 0x00500022, ++ 0x00600122, ++ 0x00700222, ++ 0x00800322, ++ 0x00900422, ++ 0x00a00522, ++ 0x00b00622, ++ 0x00c00722, ++ 0x00d00822, ++ 0x00f00922, ++ 0x00100a22, ++ 0x00200b22, ++ 0x00300c22, ++ 0x00400d22, ++ 0x00500e22, ++ 0x00600f22, ++}; ++ ++static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = { ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x0007, ++ 0x0005, ++ 0x0006, ++ 0x0004, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ 0x000b, ++ 0x000b, ++ 0x000a, ++ 0x000a, ++ ++}; ++ ++static const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = { ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0005, ++ 0x0002, ++ 0x0000, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++ 0x0007, ++ 0x0007, ++ 0x0002, ++ 0x0002, ++}; ++ ++static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = { ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++ 0x0002, ++ 0x0008, ++ 0x0004, ++ 0x0001, ++}; ++ ++static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++ 0x000a, ++ 0x0009, ++ 0x0006, ++ 0x0005, ++}; ++ ++static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++ 0x0004, ++ 0x0004, ++ 0x0002, ++ 0x0002, ++}; ++ ++static const u8 dot11lcn_nf_table_rev0[] = { ++ 0x5f, ++ 0x36, ++ 0x29, ++ 0x1f, ++ 0x5f, ++ 0x36, ++ 0x29, ++ 0x1f, ++ 0x5f, ++ 0x36, ++ 0x29, ++ 0x1f, ++ 0x5f, ++ 0x36, ++ 0x29, ++ 0x1f, ++}; ++ ++static const u8 dot11lcn_gain_val_tbl_rev0[] = { ++ 0x09, ++ 0x0f, ++ 0x14, ++ 0x18, ++ 0xfe, ++ 0x07, ++ 0x0b, ++ 0x0f, ++ 0xfb, ++ 0xfe, ++ 0x01, ++ 0x05, ++ 0x08, ++ 0x0b, ++ 0x0e, ++ 0x11, ++ 0x14, ++ 0x17, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0x06, ++ 0x09, ++ 0x0c, ++ 0x0f, ++ 0x12, ++ 0x15, ++ 0x18, ++ 0x1b, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x03, ++ 0xeb, ++ 0x00, ++ 0x00, ++}; ++ ++static const u8 dot11lcn_spur_tbl_rev0[] = { ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x02, ++ 0x03, ++ 0x01, ++ 0x03, ++ 0x02, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x02, ++ 0x03, ++ 0x01, ++ 0x03, ++ 0x02, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++ 0x01, ++}; ++ ++static const u16 dot11lcn_unsup_mcs_tbl_rev0[] = { ++ 0x001a, ++ 0x0034, ++ 0x004e, ++ 0x0068, ++ 0x009c, ++ 0x00d0, ++ 0x00ea, ++ 0x0104, ++ 0x0034, ++ 0x0068, ++ 0x009c, ++ 0x00d0, ++ 0x0138, ++ 0x01a0, ++ 0x01d4, ++ 0x0208, ++ 0x004e, ++ 0x009c, ++ 0x00ea, ++ 0x0138, ++ 0x01d4, ++ 0x0270, ++ 0x02be, ++ 0x030c, ++ 0x0068, ++ 0x00d0, ++ 0x0138, ++ 0x01a0, ++ 0x0270, ++ 0x0340, ++ 0x03a8, ++ 0x0410, ++ 0x0018, ++ 0x009c, ++ 0x00d0, ++ 0x0104, ++ 0x00ea, ++ 0x0138, ++ 0x0186, ++ 0x00d0, ++ 0x0104, ++ 0x0104, ++ 0x0138, ++ 0x016c, ++ 0x016c, ++ 0x01a0, ++ 0x0138, ++ 0x0186, ++ 0x0186, ++ 0x01d4, ++ 0x0222, ++ 0x0222, ++ 0x0270, ++ 0x0104, ++ 0x0138, ++ 0x016c, ++ 0x0138, ++ 0x016c, ++ 0x01a0, ++ 0x01d4, ++ 0x01a0, ++ 0x01d4, ++ 0x0208, ++ 0x0208, ++ 0x023c, ++ 0x0186, ++ 0x01d4, ++ 0x0222, ++ 0x01d4, ++ 0x0222, ++ 0x0270, ++ 0x02be, ++ 0x0270, ++ 0x02be, ++ 0x030c, ++ 0x030c, ++ 0x035a, ++ 0x0036, ++ 0x006c, ++ 0x00a2, ++ 0x00d8, ++ 0x0144, ++ 0x01b0, ++ 0x01e6, ++ 0x021c, ++ 0x006c, ++ 0x00d8, ++ 0x0144, ++ 0x01b0, ++ 0x0288, ++ 0x0360, ++ 0x03cc, ++ 0x0438, ++ 0x00a2, ++ 0x0144, ++ 0x01e6, ++ 0x0288, ++ 0x03cc, ++ 0x0510, ++ 0x05b2, ++ 0x0654, ++ 0x00d8, ++ 0x01b0, ++ 0x0288, ++ 0x0360, ++ 0x0510, ++ 0x06c0, ++ 0x0798, ++ 0x0870, ++ 0x0018, ++ 0x0144, ++ 0x01b0, ++ 0x021c, ++ 0x01e6, ++ 0x0288, ++ 0x032a, ++ 0x01b0, ++ 0x021c, ++ 0x021c, ++ 0x0288, ++ 0x02f4, ++ 0x02f4, ++ 0x0360, ++ 0x0288, ++ 0x032a, ++ 0x032a, ++ 0x03cc, ++ 0x046e, ++ 0x046e, ++ 0x0510, ++ 0x021c, ++ 0x0288, ++ 0x02f4, ++ 0x0288, ++ 0x02f4, ++ 0x0360, ++ 0x03cc, ++ 0x0360, ++ 0x03cc, ++ 0x0438, ++ 0x0438, ++ 0x04a4, ++ 0x032a, ++ 0x03cc, ++ 0x046e, ++ 0x03cc, ++ 0x046e, ++ 0x0510, ++ 0x05b2, ++ 0x0510, ++ 0x05b2, ++ 0x0654, ++ 0x0654, ++ 0x06f6, ++}; ++ ++static const u16 dot11lcn_iq_local_tbl_rev0[] = { ++ 0x0200, ++ 0x0300, ++ 0x0400, ++ 0x0600, ++ 0x0800, ++ 0x0b00, ++ 0x1000, ++ 0x1001, ++ 0x1002, ++ 0x1003, ++ 0x1004, ++ 0x1005, ++ 0x1006, ++ 0x1007, ++ 0x1707, ++ 0x2007, ++ 0x2d07, ++ 0x4007, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0200, ++ 0x0300, ++ 0x0400, ++ 0x0600, ++ 0x0800, ++ 0x0b00, ++ 0x1000, ++ 0x1001, ++ 0x1002, ++ 0x1003, ++ 0x1004, ++ 0x1005, ++ 0x1006, ++ 0x1007, ++ 0x1707, ++ 0x2007, ++ 0x2d07, ++ 0x4007, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x4000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u32 dot11lcn_papd_compdelta_tbl_rev0[] = { ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++ 0x00080000, ++}; ++ ++const struct phytbl_info dot11lcnphytbl_info_rev0[] = { ++ {&dot11lcn_min_sig_sq_tbl_rev0, ++ sizeof(dot11lcn_min_sig_sq_tbl_rev0) / ++ sizeof(dot11lcn_min_sig_sq_tbl_rev0[0]), 2, 0, 16} ++ , ++ {&dot11lcn_noise_scale_tbl_rev0, ++ sizeof(dot11lcn_noise_scale_tbl_rev0) / ++ sizeof(dot11lcn_noise_scale_tbl_rev0[0]), 1, 0, 16} ++ , ++ {&dot11lcn_fltr_ctrl_tbl_rev0, ++ sizeof(dot11lcn_fltr_ctrl_tbl_rev0) / ++ sizeof(dot11lcn_fltr_ctrl_tbl_rev0[0]), 11, 0, 32} ++ , ++ {&dot11lcn_ps_ctrl_tbl_rev0, ++ sizeof(dot11lcn_ps_ctrl_tbl_rev0) / ++ sizeof(dot11lcn_ps_ctrl_tbl_rev0[0]), 12, 0, 32} ++ , ++ {&dot11lcn_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} ++ , ++ {&dot11lcn_aux_gain_idx_tbl_rev0, ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / ++ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} ++ , ++ {&dot11lcn_sw_ctrl_tbl_rev0, ++ sizeof(dot11lcn_sw_ctrl_tbl_rev0) / ++ sizeof(dot11lcn_sw_ctrl_tbl_rev0[0]), 15, 0, 16} ++ , ++ {&dot11lcn_nf_table_rev0, ++ sizeof(dot11lcn_nf_table_rev0) / sizeof(dot11lcn_nf_table_rev0[0]), 16, ++ 0, 8} ++ , ++ {&dot11lcn_gain_val_tbl_rev0, ++ sizeof(dot11lcn_gain_val_tbl_rev0) / ++ sizeof(dot11lcn_gain_val_tbl_rev0[0]), 17, 0, 8} ++ , ++ {&dot11lcn_gain_tbl_rev0, ++ sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, ++ 0, 32} ++ , ++ {&dot11lcn_spur_tbl_rev0, ++ sizeof(dot11lcn_spur_tbl_rev0) / sizeof(dot11lcn_spur_tbl_rev0[0]), 20, ++ 0, 8} ++ , ++ {&dot11lcn_unsup_mcs_tbl_rev0, ++ sizeof(dot11lcn_unsup_mcs_tbl_rev0) / ++ sizeof(dot11lcn_unsup_mcs_tbl_rev0[0]), 23, 0, 16} ++ , ++ {&dot11lcn_iq_local_tbl_rev0, ++ sizeof(dot11lcn_iq_local_tbl_rev0) / ++ sizeof(dot11lcn_iq_local_tbl_rev0[0]), 0, 0, 16} ++ , ++ {&dot11lcn_papd_compdelta_tbl_rev0, ++ sizeof(dot11lcn_papd_compdelta_tbl_rev0) / ++ sizeof(dot11lcn_papd_compdelta_tbl_rev0[0]), 24, 0, 32} ++ , ++}; ++ ++const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = { ++ &dot11lcn_sw_ctrl_tbl_4313_rev0, ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) / ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16 ++}; ++ ++const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = { ++ &dot11lcn_sw_ctrl_tbl_4313_epa_rev0, ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) / ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16 ++}; ++ ++const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa = { ++ &dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo, ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) / ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16 ++}; ++ ++const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250 = { ++ &dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0, ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) / ++ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16 ++}; ++ ++const u32 dot11lcnphytbl_info_sz_rev0 = ++ sizeof(dot11lcnphytbl_info_rev0) / sizeof(dot11lcnphytbl_info_rev0[0]); ++ ++const struct lcnphy_tx_gain_tbl_entry ++dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = { ++ {3, 0, 31, 0, 72}, ++ {3, 0, 31, 0, 70}, ++ {3, 0, 31, 0, 68}, ++ {3, 0, 30, 0, 67}, ++ {3, 0, 29, 0, 68}, ++ {3, 0, 28, 0, 68}, ++ {3, 0, 27, 0, 69}, ++ {3, 0, 26, 0, 70}, ++ {3, 0, 25, 0, 70}, ++ {3, 0, 24, 0, 71}, ++ {3, 0, 23, 0, 72}, ++ {3, 0, 23, 0, 70}, ++ {3, 0, 22, 0, 71}, ++ {3, 0, 21, 0, 72}, ++ {3, 0, 21, 0, 70}, ++ {3, 0, 21, 0, 68}, ++ {3, 0, 21, 0, 66}, ++ {3, 0, 21, 0, 64}, ++ {3, 0, 21, 0, 63}, ++ {3, 0, 20, 0, 64}, ++ {3, 0, 19, 0, 65}, ++ {3, 0, 19, 0, 64}, ++ {3, 0, 18, 0, 65}, ++ {3, 0, 18, 0, 64}, ++ {3, 0, 17, 0, 65}, ++ {3, 0, 17, 0, 64}, ++ {3, 0, 16, 0, 65}, ++ {3, 0, 16, 0, 64}, ++ {3, 0, 16, 0, 62}, ++ {3, 0, 16, 0, 60}, ++ {3, 0, 16, 0, 58}, ++ {3, 0, 15, 0, 61}, ++ {3, 0, 15, 0, 59}, ++ {3, 0, 14, 0, 61}, ++ {3, 0, 14, 0, 60}, ++ {3, 0, 14, 0, 58}, ++ {3, 0, 13, 0, 60}, ++ {3, 0, 13, 0, 59}, ++ {3, 0, 12, 0, 62}, ++ {3, 0, 12, 0, 60}, ++ {3, 0, 12, 0, 58}, ++ {3, 0, 11, 0, 62}, ++ {3, 0, 11, 0, 60}, ++ {3, 0, 11, 0, 59}, ++ {3, 0, 11, 0, 57}, ++ {3, 0, 10, 0, 61}, ++ {3, 0, 10, 0, 59}, ++ {3, 0, 10, 0, 57}, ++ {3, 0, 9, 0, 62}, ++ {3, 0, 9, 0, 60}, ++ {3, 0, 9, 0, 58}, ++ {3, 0, 9, 0, 57}, ++ {3, 0, 8, 0, 62}, ++ {3, 0, 8, 0, 60}, ++ {3, 0, 8, 0, 58}, ++ {3, 0, 8, 0, 57}, ++ {3, 0, 8, 0, 55}, ++ {3, 0, 7, 0, 61}, ++ {3, 0, 7, 0, 60}, ++ {3, 0, 7, 0, 58}, ++ {3, 0, 7, 0, 56}, ++ {3, 0, 7, 0, 55}, ++ {3, 0, 6, 0, 62}, ++ {3, 0, 6, 0, 60}, ++ {3, 0, 6, 0, 58}, ++ {3, 0, 6, 0, 57}, ++ {3, 0, 6, 0, 55}, ++ {3, 0, 6, 0, 54}, ++ {3, 0, 6, 0, 52}, ++ {3, 0, 5, 0, 61}, ++ {3, 0, 5, 0, 59}, ++ {3, 0, 5, 0, 57}, ++ {3, 0, 5, 0, 56}, ++ {3, 0, 5, 0, 54}, ++ {3, 0, 5, 0, 53}, ++ {3, 0, 5, 0, 51}, ++ {3, 0, 4, 0, 62}, ++ {3, 0, 4, 0, 60}, ++ {3, 0, 4, 0, 58}, ++ {3, 0, 4, 0, 57}, ++ {3, 0, 4, 0, 55}, ++ {3, 0, 4, 0, 54}, ++ {3, 0, 4, 0, 52}, ++ {3, 0, 4, 0, 51}, ++ {3, 0, 4, 0, 49}, ++ {3, 0, 4, 0, 48}, ++ {3, 0, 4, 0, 46}, ++ {3, 0, 3, 0, 60}, ++ {3, 0, 3, 0, 58}, ++ {3, 0, 3, 0, 57}, ++ {3, 0, 3, 0, 55}, ++ {3, 0, 3, 0, 54}, ++ {3, 0, 3, 0, 52}, ++ {3, 0, 3, 0, 51}, ++ {3, 0, 3, 0, 49}, ++ {3, 0, 3, 0, 48}, ++ {3, 0, 3, 0, 46}, ++ {3, 0, 3, 0, 45}, ++ {3, 0, 3, 0, 44}, ++ {3, 0, 3, 0, 43}, ++ {3, 0, 3, 0, 41}, ++ {3, 0, 2, 0, 61}, ++ {3, 0, 2, 0, 59}, ++ {3, 0, 2, 0, 57}, ++ {3, 0, 2, 0, 56}, ++ {3, 0, 2, 0, 54}, ++ {3, 0, 2, 0, 53}, ++ {3, 0, 2, 0, 51}, ++ {3, 0, 2, 0, 50}, ++ {3, 0, 2, 0, 48}, ++ {3, 0, 2, 0, 47}, ++ {3, 0, 2, 0, 46}, ++ {3, 0, 2, 0, 44}, ++ {3, 0, 2, 0, 43}, ++ {3, 0, 2, 0, 42}, ++ {3, 0, 2, 0, 41}, ++ {3, 0, 2, 0, 39}, ++ {3, 0, 2, 0, 38}, ++ {3, 0, 2, 0, 37}, ++ {3, 0, 2, 0, 36}, ++ {3, 0, 2, 0, 35}, ++ {3, 0, 2, 0, 34}, ++ {3, 0, 2, 0, 33}, ++ {3, 0, 2, 0, 32}, ++ {3, 0, 1, 0, 63}, ++ {3, 0, 1, 0, 61}, ++ {3, 0, 1, 0, 59}, ++ {3, 0, 1, 0, 57}, ++}; ++ ++const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[128] = { ++ {7, 0, 31, 0, 72}, ++ {7, 0, 31, 0, 70}, ++ {7, 0, 31, 0, 68}, ++ {7, 0, 30, 0, 67}, ++ {7, 0, 29, 0, 68}, ++ {7, 0, 28, 0, 68}, ++ {7, 0, 27, 0, 69}, ++ {7, 0, 26, 0, 70}, ++ {7, 0, 25, 0, 70}, ++ {7, 0, 24, 0, 71}, ++ {7, 0, 23, 0, 72}, ++ {7, 0, 23, 0, 70}, ++ {7, 0, 22, 0, 71}, ++ {7, 0, 21, 0, 72}, ++ {7, 0, 21, 0, 70}, ++ {7, 0, 21, 0, 68}, ++ {7, 0, 21, 0, 66}, ++ {7, 0, 21, 0, 64}, ++ {7, 0, 21, 0, 63}, ++ {7, 0, 20, 0, 64}, ++ {7, 0, 19, 0, 65}, ++ {7, 0, 19, 0, 64}, ++ {7, 0, 18, 0, 65}, ++ {7, 0, 18, 0, 64}, ++ {7, 0, 17, 0, 65}, ++ {7, 0, 17, 0, 64}, ++ {7, 0, 16, 0, 65}, ++ {7, 0, 16, 0, 64}, ++ {7, 0, 16, 0, 62}, ++ {7, 0, 16, 0, 60}, ++ {7, 0, 16, 0, 58}, ++ {7, 0, 15, 0, 61}, ++ {7, 0, 15, 0, 59}, ++ {7, 0, 14, 0, 61}, ++ {7, 0, 14, 0, 60}, ++ {7, 0, 14, 0, 58}, ++ {7, 0, 13, 0, 60}, ++ {7, 0, 13, 0, 59}, ++ {7, 0, 12, 0, 62}, ++ {7, 0, 12, 0, 60}, ++ {7, 0, 12, 0, 58}, ++ {7, 0, 11, 0, 62}, ++ {7, 0, 11, 0, 60}, ++ {7, 0, 11, 0, 59}, ++ {7, 0, 11, 0, 57}, ++ {7, 0, 10, 0, 61}, ++ {7, 0, 10, 0, 59}, ++ {7, 0, 10, 0, 57}, ++ {7, 0, 9, 0, 62}, ++ {7, 0, 9, 0, 60}, ++ {7, 0, 9, 0, 58}, ++ {7, 0, 9, 0, 57}, ++ {7, 0, 8, 0, 62}, ++ {7, 0, 8, 0, 60}, ++ {7, 0, 8, 0, 58}, ++ {7, 0, 8, 0, 57}, ++ {7, 0, 8, 0, 55}, ++ {7, 0, 7, 0, 61}, ++ {7, 0, 7, 0, 60}, ++ {7, 0, 7, 0, 58}, ++ {7, 0, 7, 0, 56}, ++ {7, 0, 7, 0, 55}, ++ {7, 0, 6, 0, 62}, ++ {7, 0, 6, 0, 60}, ++ {7, 0, 6, 0, 58}, ++ {7, 0, 6, 0, 57}, ++ {7, 0, 6, 0, 55}, ++ {7, 0, 6, 0, 54}, ++ {7, 0, 6, 0, 52}, ++ {7, 0, 5, 0, 61}, ++ {7, 0, 5, 0, 59}, ++ {7, 0, 5, 0, 57}, ++ {7, 0, 5, 0, 56}, ++ {7, 0, 5, 0, 54}, ++ {7, 0, 5, 0, 53}, ++ {7, 0, 5, 0, 51}, ++ {7, 0, 4, 0, 62}, ++ {7, 0, 4, 0, 60}, ++ {7, 0, 4, 0, 58}, ++ {7, 0, 4, 0, 57}, ++ {7, 0, 4, 0, 55}, ++ {7, 0, 4, 0, 54}, ++ {7, 0, 4, 0, 52}, ++ {7, 0, 4, 0, 51}, ++ {7, 0, 4, 0, 49}, ++ {7, 0, 4, 0, 48}, ++ {7, 0, 4, 0, 46}, ++ {7, 0, 3, 0, 60}, ++ {7, 0, 3, 0, 58}, ++ {7, 0, 3, 0, 57}, ++ {7, 0, 3, 0, 55}, ++ {7, 0, 3, 0, 54}, ++ {7, 0, 3, 0, 52}, ++ {7, 0, 3, 0, 51}, ++ {7, 0, 3, 0, 49}, ++ {7, 0, 3, 0, 48}, ++ {7, 0, 3, 0, 46}, ++ {7, 0, 3, 0, 45}, ++ {7, 0, 3, 0, 44}, ++ {7, 0, 3, 0, 43}, ++ {7, 0, 3, 0, 41}, ++ {7, 0, 2, 0, 61}, ++ {7, 0, 2, 0, 59}, ++ {7, 0, 2, 0, 57}, ++ {7, 0, 2, 0, 56}, ++ {7, 0, 2, 0, 54}, ++ {7, 0, 2, 0, 53}, ++ {7, 0, 2, 0, 51}, ++ {7, 0, 2, 0, 50}, ++ {7, 0, 2, 0, 48}, ++ {7, 0, 2, 0, 47}, ++ {7, 0, 2, 0, 46}, ++ {7, 0, 2, 0, 44}, ++ {7, 0, 2, 0, 43}, ++ {7, 0, 2, 0, 42}, ++ {7, 0, 2, 0, 41}, ++ {7, 0, 2, 0, 39}, ++ {7, 0, 2, 0, 38}, ++ {7, 0, 2, 0, 37}, ++ {7, 0, 2, 0, 36}, ++ {7, 0, 2, 0, 35}, ++ {7, 0, 2, 0, 34}, ++ {7, 0, 2, 0, 33}, ++ {7, 0, 2, 0, 32}, ++ {7, 0, 1, 0, 63}, ++ {7, 0, 1, 0, 61}, ++ {7, 0, 1, 0, 59}, ++ {7, 0, 1, 0, 57}, ++}; ++ ++const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[128] = { ++ {255, 255, 0xf0, 0, 152}, ++ {255, 255, 0xf0, 0, 147}, ++ {255, 255, 0xf0, 0, 143}, ++ {255, 255, 0xf0, 0, 139}, ++ {255, 255, 0xf0, 0, 135}, ++ {255, 255, 0xf0, 0, 131}, ++ {255, 255, 0xf0, 0, 128}, ++ {255, 255, 0xf0, 0, 124}, ++ {255, 255, 0xf0, 0, 121}, ++ {255, 255, 0xf0, 0, 117}, ++ {255, 255, 0xf0, 0, 114}, ++ {255, 255, 0xf0, 0, 111}, ++ {255, 255, 0xf0, 0, 107}, ++ {255, 255, 0xf0, 0, 104}, ++ {255, 255, 0xf0, 0, 101}, ++ {255, 255, 0xf0, 0, 99}, ++ {255, 255, 0xf0, 0, 96}, ++ {255, 255, 0xf0, 0, 93}, ++ {255, 255, 0xf0, 0, 90}, ++ {255, 255, 0xf0, 0, 88}, ++ {255, 255, 0xf0, 0, 85}, ++ {255, 255, 0xf0, 0, 83}, ++ {255, 255, 0xf0, 0, 81}, ++ {255, 255, 0xf0, 0, 78}, ++ {255, 255, 0xf0, 0, 76}, ++ {255, 255, 0xf0, 0, 74}, ++ {255, 255, 0xf0, 0, 72}, ++ {255, 255, 0xf0, 0, 70}, ++ {255, 255, 0xf0, 0, 68}, ++ {255, 255, 0xf0, 0, 66}, ++ {255, 255, 0xf0, 0, 64}, ++ {255, 248, 0xf0, 0, 64}, ++ {255, 241, 0xf0, 0, 64}, ++ {255, 251, 0xe0, 0, 64}, ++ {255, 244, 0xe0, 0, 64}, ++ {255, 254, 0xd0, 0, 64}, ++ {255, 246, 0xd0, 0, 64}, ++ {255, 239, 0xd0, 0, 64}, ++ {255, 249, 0xc0, 0, 64}, ++ {255, 242, 0xc0, 0, 64}, ++ {255, 255, 0xb0, 0, 64}, ++ {255, 248, 0xb0, 0, 64}, ++ {255, 241, 0xb0, 0, 64}, ++ {255, 254, 0xa0, 0, 64}, ++ {255, 246, 0xa0, 0, 64}, ++ {255, 239, 0xa0, 0, 64}, ++ {255, 255, 0x90, 0, 64}, ++ {255, 248, 0x90, 0, 64}, ++ {255, 241, 0x90, 0, 64}, ++ {255, 234, 0x90, 0, 64}, ++ {255, 255, 0x80, 0, 64}, ++ {255, 248, 0x80, 0, 64}, ++ {255, 241, 0x80, 0, 64}, ++ {255, 234, 0x80, 0, 64}, ++ {255, 255, 0x70, 0, 64}, ++ {255, 248, 0x70, 0, 64}, ++ {255, 241, 0x70, 0, 64}, ++ {255, 234, 0x70, 0, 64}, ++ {255, 227, 0x70, 0, 64}, ++ {255, 221, 0x70, 0, 64}, ++ {255, 215, 0x70, 0, 64}, ++ {255, 208, 0x70, 0, 64}, ++ {255, 203, 0x70, 0, 64}, ++ {255, 197, 0x70, 0, 64}, ++ {255, 255, 0x60, 0, 64}, ++ {255, 248, 0x60, 0, 64}, ++ {255, 241, 0x60, 0, 64}, ++ {255, 234, 0x60, 0, 64}, ++ {255, 227, 0x60, 0, 64}, ++ {255, 221, 0x60, 0, 64}, ++ {255, 255, 0x50, 0, 64}, ++ {255, 248, 0x50, 0, 64}, ++ {255, 241, 0x50, 0, 64}, ++ {255, 234, 0x50, 0, 64}, ++ {255, 227, 0x50, 0, 64}, ++ {255, 221, 0x50, 0, 64}, ++ {255, 215, 0x50, 0, 64}, ++ {255, 208, 0x50, 0, 64}, ++ {255, 255, 0x40, 0, 64}, ++ {255, 248, 0x40, 0, 64}, ++ {255, 241, 0x40, 0, 64}, ++ {255, 234, 0x40, 0, 64}, ++ {255, 227, 0x40, 0, 64}, ++ {255, 221, 0x40, 0, 64}, ++ {255, 215, 0x40, 0, 64}, ++ {255, 208, 0x40, 0, 64}, ++ {255, 203, 0x40, 0, 64}, ++ {255, 197, 0x40, 0, 64}, ++ {255, 255, 0x30, 0, 64}, ++ {255, 248, 0x30, 0, 64}, ++ {255, 241, 0x30, 0, 64}, ++ {255, 234, 0x30, 0, 64}, ++ {255, 227, 0x30, 0, 64}, ++ {255, 221, 0x30, 0, 64}, ++ {255, 215, 0x30, 0, 64}, ++ {255, 208, 0x30, 0, 64}, ++ {255, 203, 0x30, 0, 64}, ++ {255, 197, 0x30, 0, 64}, ++ {255, 191, 0x30, 0, 64}, ++ {255, 186, 0x30, 0, 64}, ++ {255, 181, 0x30, 0, 64}, ++ {255, 175, 0x30, 0, 64}, ++ {255, 255, 0x20, 0, 64}, ++ {255, 248, 0x20, 0, 64}, ++ {255, 241, 0x20, 0, 64}, ++ {255, 234, 0x20, 0, 64}, ++ {255, 227, 0x20, 0, 64}, ++ {255, 221, 0x20, 0, 64}, ++ {255, 215, 0x20, 0, 64}, ++ {255, 208, 0x20, 0, 64}, ++ {255, 203, 0x20, 0, 64}, ++ {255, 197, 0x20, 0, 64}, ++ {255, 191, 0x20, 0, 64}, ++ {255, 186, 0x20, 0, 64}, ++ {255, 181, 0x20, 0, 64}, ++ {255, 175, 0x20, 0, 64}, ++ {255, 170, 0x20, 0, 64}, ++ {255, 166, 0x20, 0, 64}, ++ {255, 161, 0x20, 0, 64}, ++ {255, 156, 0x20, 0, 64}, ++ {255, 152, 0x20, 0, 64}, ++ {255, 148, 0x20, 0, 64}, ++ {255, 143, 0x20, 0, 64}, ++ {255, 139, 0x20, 0, 64}, ++ {255, 135, 0x20, 0, 64}, ++ {255, 132, 0x20, 0, 64}, ++ {255, 255, 0x10, 0, 64}, ++ {255, 248, 0x10, 0, 64}, ++}; +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h.orig 2011-11-09 13:46:58.278800221 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h 2011-11-09 13:47:17.036565717 -0500 +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include "phy_int.h" ++ ++extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[]; ++extern const u32 dot11lcnphytbl_rx_gain_info_sz_rev0; ++extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313; ++extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa; ++extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa_combo; ++extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa; ++extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250; ++ ++extern const struct phytbl_info dot11lcnphytbl_info_rev0[]; ++extern const u32 dot11lcnphytbl_info_sz_rev0; ++ ++extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[]; ++extern const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz; ++ ++extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[]; ++extern const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz; ++ ++extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[]; ++ ++extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[]; ++ ++struct lcnphy_tx_gain_tbl_entry { ++ unsigned char gm; ++ unsigned char pga; ++ unsigned char pad; ++ unsigned char dac; ++ unsigned char bb_mult; ++}; ++ ++extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[]; ++ ++extern const struct ++lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_extPA_gaintable_rev0[]; ++ ++extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[]; +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c.orig 2011-11-09 13:46:58.282800170 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c 2011-11-09 13:47:17.040565666 -0500 +@@ -0,0 +1,10630 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include "phytbl_n.h" ++ ++static const u32 frame_struct_rev0[] = { ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x09804506, ++ 0x00100030, ++ 0x09804507, ++ 0x00100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a0c, ++ 0x00100004, ++ 0x01000a0d, ++ 0x00100024, ++ 0x0980450e, ++ 0x00100034, ++ 0x0980450f, ++ 0x00100034, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a04, ++ 0x00100000, ++ 0x11008a05, ++ 0x00100020, ++ 0x1980c506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x01800504, ++ 0x00100030, ++ 0x11808505, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000a04, ++ 0x00100000, ++ 0x11008a05, ++ 0x00100020, ++ 0x21810506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x1980c50e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x0180050c, ++ 0x00100038, ++ 0x1180850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x1980c506, ++ 0x00100030, ++ 0x1980c506, ++ 0x00100030, ++ 0x11808504, ++ 0x00100030, ++ 0x3981ca05, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x10008a04, ++ 0x00100000, ++ 0x3981ca05, ++ 0x00100030, ++ 0x1980c506, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a0c, ++ 0x00100008, ++ 0x01000a0d, ++ 0x00100028, ++ 0x1980c50e, ++ 0x00100038, ++ 0x1980c50e, ++ 0x00100038, ++ 0x1180850c, ++ 0x00100038, ++ 0x3981ca0d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x10008a0c, ++ 0x00100008, ++ 0x3981ca0d, ++ 0x00100038, ++ 0x1980c50e, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x02001405, ++ 0x00100040, ++ 0x0b004a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x43020a04, ++ 0x00100060, ++ 0x1b00ca05, ++ 0x00100060, ++ 0x23010a07, ++ 0x01500060, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x13008a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x0200140d, ++ 0x00100050, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x50029404, ++ 0x00100000, ++ 0x32019405, ++ 0x00100040, ++ 0x0b004a06, ++ 0x01900060, ++ 0x0b004a06, ++ 0x01900060, ++ 0x5b02ca04, ++ 0x00100060, ++ 0x3b01d405, ++ 0x00100060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x5802d404, ++ 0x00100000, ++ 0x3b01d405, ++ 0x00100060, ++ 0x0b004a06, ++ 0x01900060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x5002940c, ++ 0x00100010, ++ 0x3201940d, ++ 0x00100050, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x5b02ca0c, ++ 0x00100070, ++ 0x3b01d40d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x5802d40c, ++ 0x00100010, ++ 0x3b01d40d, ++ 0x00100070, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x000f4800, ++ 0x62031405, ++ 0x00100040, ++ 0x53028a06, ++ 0x01900060, ++ 0x53028a07, ++ 0x01900060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x000f4808, ++ 0x6203140d, ++ 0x00100048, ++ 0x53028a0e, ++ 0x01900068, ++ 0x53028a0f, ++ 0x01900068, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100004, ++ 0x11008a0d, ++ 0x00100024, ++ 0x1980c50e, ++ 0x00100034, ++ 0x2181050e, ++ 0x00100034, ++ 0x2181050e, ++ 0x00100034, ++ 0x0180050c, ++ 0x00100038, ++ 0x1180850d, ++ 0x00100038, ++ 0x1181850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x1181850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x0180c506, ++ 0x00100030, ++ 0x0180c506, ++ 0x00100030, ++ 0x2180c50c, ++ 0x00100030, ++ 0x49820a0d, ++ 0x0016a130, ++ 0x41824a0d, ++ 0x0016a130, ++ 0x2981450f, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x2000ca0c, ++ 0x00100000, ++ 0x49820a0d, ++ 0x0016a130, ++ 0x1980c50e, ++ 0x00100030, ++ 0x41824a0d, ++ 0x0016a130, ++ 0x2981450f, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100008, ++ 0x0200140d, ++ 0x00100048, ++ 0x0b004a0e, ++ 0x01900068, ++ 0x13008a0e, ++ 0x01900068, ++ 0x13008a0e, ++ 0x01900068, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x1b014a0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x1b014a0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x50029404, ++ 0x00100000, ++ 0x32019405, ++ 0x00100040, ++ 0x03004a06, ++ 0x01900060, ++ 0x03004a06, ++ 0x01900060, ++ 0x6b030a0c, ++ 0x00100060, ++ 0x4b02140d, ++ 0x0016a160, ++ 0x4302540d, ++ 0x0016a160, ++ 0x23010a0f, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x6b03140c, ++ 0x00100060, ++ 0x4b02140d, ++ 0x0016a160, ++ 0x0b004a0e, ++ 0x01900060, ++ 0x4302540d, ++ 0x0016a160, ++ 0x23010a0f, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x53028a06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x43020a04, ++ 0x00100060, ++ 0x1b00ca05, ++ 0x00100060, ++ 0x53028a07, ++ 0x0190c060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x53028a0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x53028a0f, ++ 0x0190c070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x53028a07, ++ 0x0190c060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x53028a0f, ++ 0x0190c070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u8 frame_lut_rev0[] = { ++ 0x02, ++ 0x04, ++ 0x14, ++ 0x14, ++ 0x03, ++ 0x05, ++ 0x16, ++ 0x16, ++ 0x0a, ++ 0x0c, ++ 0x1c, ++ 0x1c, ++ 0x0b, ++ 0x0d, ++ 0x1e, ++ 0x1e, ++ 0x06, ++ 0x08, ++ 0x18, ++ 0x18, ++ 0x07, ++ 0x09, ++ 0x1a, ++ 0x1a, ++ 0x0e, ++ 0x10, ++ 0x20, ++ 0x28, ++ 0x0f, ++ 0x11, ++ 0x22, ++ 0x2a, ++}; ++ ++static const u32 tmap_tbl_rev0[] = { ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x000aa888, ++ 0x88880000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00011111, ++ 0x11110000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00088aaa, ++ 0xaaaa0000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xaaa8aaa0, ++ 0x8aaa8aaa, ++ 0xaa8a8a8a, ++ 0x000aaa88, ++ 0x8aaa0000, ++ 0xaaa8a888, ++ 0x8aa88a8a, ++ 0x8a88a888, ++ 0x08080a00, ++ 0x0a08080a, ++ 0x080a0a08, ++ 0x00080808, ++ 0x080a0000, ++ 0x080a0808, ++ 0x080a0808, ++ 0x0a0a0a08, ++ 0xa0a0a0a0, ++ 0x80a0a080, ++ 0x8080a0a0, ++ 0x00008080, ++ 0x80a00000, ++ 0x80a080a0, ++ 0xa080a0a0, ++ 0x8080a0a0, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x99999000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x22000000, ++ 0x2222b222, ++ 0x22222222, ++ 0x222222b2, ++ 0xb2222220, ++ 0x22222222, ++ 0x22d22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333b333, ++ 0x33333333, ++ 0x333333b3, ++ 0xb3333330, ++ 0x33333333, ++ 0x33d33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x99b99b00, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb99, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x22222200, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0x22222222, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x11111111, ++ 0xf1111111, ++ 0x11111111, ++ 0x11f11111, ++ 0x01111111, ++ 0xbb9bb900, ++ 0xb9b9bb99, ++ 0xb99bbbbb, ++ 0xbbbb9b9b, ++ 0xb9bb99bb, ++ 0xb99999b9, ++ 0xb9b9b99b, ++ 0x00000bbb, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88aa, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x0a888aaa, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00000aaa, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0xbbbbbb00, ++ 0x999bbbbb, ++ 0x9bb99b9b, ++ 0xb9b9b9bb, ++ 0xb9b99bbb, ++ 0xb9b9b9bb, ++ 0xb9bb9b99, ++ 0x00000999, ++ 0x8a000000, ++ 0xaa88a888, ++ 0xa88888aa, ++ 0xa88a8a88, ++ 0xa88aa88a, ++ 0x88a8aaaa, ++ 0xa8aa8aaa, ++ 0x0888a88a, ++ 0x0b0b0b00, ++ 0x090b0b0b, ++ 0x0b090b0b, ++ 0x0909090b, ++ 0x09090b0b, ++ 0x09090b0b, ++ 0x09090b09, ++ 0x00000909, ++ 0x0a000000, ++ 0x0a080808, ++ 0x080a080a, ++ 0x080a0a08, ++ 0x080a080a, ++ 0x0808080a, ++ 0x0a0a0a08, ++ 0x0808080a, ++ 0xb0b0b000, ++ 0x9090b0b0, ++ 0x90b09090, ++ 0xb0b0b090, ++ 0xb0b090b0, ++ 0x90b0b0b0, ++ 0xb0b09090, ++ 0x00000090, ++ 0x80000000, ++ 0xa080a080, ++ 0xa08080a0, ++ 0xa0808080, ++ 0xa080a080, ++ 0x80a0a0a0, ++ 0xa0a080a0, ++ 0x00a0a0a0, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333f333, ++ 0x33333333, ++ 0x333333f3, ++ 0xf3333330, ++ 0x33333333, ++ 0x33f33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x99000000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88888000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x88a88a00, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdtrn_tbl_rev0[] = { ++ 0x061c061c, ++ 0x0050ee68, ++ 0xf592fe36, ++ 0xfe5212f6, ++ 0x00000c38, ++ 0xfe5212f6, ++ 0xf592fe36, ++ 0x0050ee68, ++ 0x061c061c, ++ 0xee680050, ++ 0xfe36f592, ++ 0x12f6fe52, ++ 0x0c380000, ++ 0x12f6fe52, ++ 0xfe36f592, ++ 0xee680050, ++ 0x061c061c, ++ 0x0050ee68, ++ 0xf592fe36, ++ 0xfe5212f6, ++ 0x00000c38, ++ 0xfe5212f6, ++ 0xf592fe36, ++ 0x0050ee68, ++ 0x061c061c, ++ 0xee680050, ++ 0xfe36f592, ++ 0x12f6fe52, ++ 0x0c380000, ++ 0x12f6fe52, ++ 0xfe36f592, ++ 0xee680050, ++ 0x05e305e3, ++ 0x004def0c, ++ 0xf5f3fe47, ++ 0xfe611246, ++ 0x00000bc7, ++ 0xfe611246, ++ 0xf5f3fe47, ++ 0x004def0c, ++ 0x05e305e3, ++ 0xef0c004d, ++ 0xfe47f5f3, ++ 0x1246fe61, ++ 0x0bc70000, ++ 0x1246fe61, ++ 0xfe47f5f3, ++ 0xef0c004d, ++ 0x05e305e3, ++ 0x004def0c, ++ 0xf5f3fe47, ++ 0xfe611246, ++ 0x00000bc7, ++ 0xfe611246, ++ 0xf5f3fe47, ++ 0x004def0c, ++ 0x05e305e3, ++ 0xef0c004d, ++ 0xfe47f5f3, ++ 0x1246fe61, ++ 0x0bc70000, ++ 0x1246fe61, ++ 0xfe47f5f3, ++ 0xef0c004d, ++ 0xfa58fa58, ++ 0xf895043b, ++ 0xff4c09c0, ++ 0xfbc6ffa8, ++ 0xfb84f384, ++ 0x0798f6f9, ++ 0x05760122, ++ 0x058409f6, ++ 0x0b500000, ++ 0x05b7f542, ++ 0x08860432, ++ 0x06ddfee7, ++ 0xfb84f384, ++ 0xf9d90664, ++ 0xf7e8025c, ++ 0x00fff7bd, ++ 0x05a805a8, ++ 0xf7bd00ff, ++ 0x025cf7e8, ++ 0x0664f9d9, ++ 0xf384fb84, ++ 0xfee706dd, ++ 0x04320886, ++ 0xf54205b7, ++ 0x00000b50, ++ 0x09f60584, ++ 0x01220576, ++ 0xf6f90798, ++ 0xf384fb84, ++ 0xffa8fbc6, ++ 0x09c0ff4c, ++ 0x043bf895, ++ 0x02d402d4, ++ 0x07de0270, ++ 0xfc96079c, ++ 0xf90afe94, ++ 0xfe00ff2c, ++ 0x02d4065d, ++ 0x092a0096, ++ 0x0014fbb8, ++ 0xfd2cfd2c, ++ 0x076afb3c, ++ 0x0096f752, ++ 0xf991fd87, ++ 0xfb2c0200, ++ 0xfeb8f960, ++ 0x08e0fc96, ++ 0x049802a8, ++ 0xfd2cfd2c, ++ 0x02a80498, ++ 0xfc9608e0, ++ 0xf960feb8, ++ 0x0200fb2c, ++ 0xfd87f991, ++ 0xf7520096, ++ 0xfb3c076a, ++ 0xfd2cfd2c, ++ 0xfbb80014, ++ 0x0096092a, ++ 0x065d02d4, ++ 0xff2cfe00, ++ 0xfe94f90a, ++ 0x079cfc96, ++ 0x027007de, ++ 0x02d402d4, ++ 0x027007de, ++ 0x079cfc96, ++ 0xfe94f90a, ++ 0xff2cfe00, ++ 0x065d02d4, ++ 0x0096092a, ++ 0xfbb80014, ++ 0xfd2cfd2c, ++ 0xfb3c076a, ++ 0xf7520096, ++ 0xfd87f991, ++ 0x0200fb2c, ++ 0xf960feb8, ++ 0xfc9608e0, ++ 0x02a80498, ++ 0xfd2cfd2c, ++ 0x049802a8, ++ 0x08e0fc96, ++ 0xfeb8f960, ++ 0xfb2c0200, ++ 0xf991fd87, ++ 0x0096f752, ++ 0x076afb3c, ++ 0xfd2cfd2c, ++ 0x0014fbb8, ++ 0x092a0096, ++ 0x02d4065d, ++ 0xfe00ff2c, ++ 0xf90afe94, ++ 0xfc96079c, ++ 0x07de0270, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x062a0000, ++ 0xfefa0759, ++ 0x08b80908, ++ 0xf396fc2d, ++ 0xf9d6045c, ++ 0xfc4ef608, ++ 0xf748f596, ++ 0x07b207bf, ++ 0x062a062a, ++ 0xf84ef841, ++ 0xf748f596, ++ 0x03b209f8, ++ 0xf9d6045c, ++ 0x0c6a03d3, ++ 0x08b80908, ++ 0x0106f8a7, ++ 0x062a0000, ++ 0xfefaf8a7, ++ 0x08b8f6f8, ++ 0xf39603d3, ++ 0xf9d6fba4, ++ 0xfc4e09f8, ++ 0xf7480a6a, ++ 0x07b2f841, ++ 0x062af9d6, ++ 0xf84e07bf, ++ 0xf7480a6a, ++ 0x03b2f608, ++ 0xf9d6fba4, ++ 0x0c6afc2d, ++ 0x08b8f6f8, ++ 0x01060759, ++ 0x062a0000, ++ 0xfefa0759, ++ 0x08b80908, ++ 0xf396fc2d, ++ 0xf9d6045c, ++ 0xfc4ef608, ++ 0xf748f596, ++ 0x07b207bf, ++ 0x062a062a, ++ 0xf84ef841, ++ 0xf748f596, ++ 0x03b209f8, ++ 0xf9d6045c, ++ 0x0c6a03d3, ++ 0x08b80908, ++ 0x0106f8a7, ++ 0x062a0000, ++ 0xfefaf8a7, ++ 0x08b8f6f8, ++ 0xf39603d3, ++ 0xf9d6fba4, ++ 0xfc4e09f8, ++ 0xf7480a6a, ++ 0x07b2f841, ++ 0x062af9d6, ++ 0xf84e07bf, ++ 0xf7480a6a, ++ 0x03b2f608, ++ 0xf9d6fba4, ++ 0x0c6afc2d, ++ 0x08b8f6f8, ++ 0x01060759, ++ 0x061c061c, ++ 0xff30009d, ++ 0xffb21141, ++ 0xfd87fb54, ++ 0xf65dfe59, ++ 0x02eef99e, ++ 0x0166f03c, ++ 0xfff809b6, ++ 0x000008a4, ++ 0x000af42b, ++ 0x00eff577, ++ 0xfa840bf2, ++ 0xfc02ff51, ++ 0x08260f67, ++ 0xfff0036f, ++ 0x0842f9c3, ++ 0x00000000, ++ 0x063df7be, ++ 0xfc910010, ++ 0xf099f7da, ++ 0x00af03fe, ++ 0xf40e057c, ++ 0x0a89ff11, ++ 0x0bd5fff6, ++ 0xf75c0000, ++ 0xf64a0008, ++ 0x0fc4fe9a, ++ 0x0662fd12, ++ 0x01a709a3, ++ 0x04ac0279, ++ 0xeebf004e, ++ 0xff6300d0, ++ 0xf9e4f9e4, ++ 0x00d0ff63, ++ 0x004eeebf, ++ 0x027904ac, ++ 0x09a301a7, ++ 0xfd120662, ++ 0xfe9a0fc4, ++ 0x0008f64a, ++ 0x0000f75c, ++ 0xfff60bd5, ++ 0xff110a89, ++ 0x057cf40e, ++ 0x03fe00af, ++ 0xf7daf099, ++ 0x0010fc91, ++ 0xf7be063d, ++ 0x00000000, ++ 0xf9c30842, ++ 0x036ffff0, ++ 0x0f670826, ++ 0xff51fc02, ++ 0x0bf2fa84, ++ 0xf57700ef, ++ 0xf42b000a, ++ 0x08a40000, ++ 0x09b6fff8, ++ 0xf03c0166, ++ 0xf99e02ee, ++ 0xfe59f65d, ++ 0xfb54fd87, ++ 0x1141ffb2, ++ 0x009dff30, ++ 0x05e30000, ++ 0xff060705, ++ 0x085408a0, ++ 0xf425fc59, ++ 0xfa1d042a, ++ 0xfc78f67a, ++ 0xf7acf60e, ++ 0x075a0766, ++ 0x05e305e3, ++ 0xf8a6f89a, ++ 0xf7acf60e, ++ 0x03880986, ++ 0xfa1d042a, ++ 0x0bdb03a7, ++ 0x085408a0, ++ 0x00faf8fb, ++ 0x05e30000, ++ 0xff06f8fb, ++ 0x0854f760, ++ 0xf42503a7, ++ 0xfa1dfbd6, ++ 0xfc780986, ++ 0xf7ac09f2, ++ 0x075af89a, ++ 0x05e3fa1d, ++ 0xf8a60766, ++ 0xf7ac09f2, ++ 0x0388f67a, ++ 0xfa1dfbd6, ++ 0x0bdbfc59, ++ 0x0854f760, ++ 0x00fa0705, ++ 0x05e30000, ++ 0xff060705, ++ 0x085408a0, ++ 0xf425fc59, ++ 0xfa1d042a, ++ 0xfc78f67a, ++ 0xf7acf60e, ++ 0x075a0766, ++ 0x05e305e3, ++ 0xf8a6f89a, ++ 0xf7acf60e, ++ 0x03880986, ++ 0xfa1d042a, ++ 0x0bdb03a7, ++ 0x085408a0, ++ 0x00faf8fb, ++ 0x05e30000, ++ 0xff06f8fb, ++ 0x0854f760, ++ 0xf42503a7, ++ 0xfa1dfbd6, ++ 0xfc780986, ++ 0xf7ac09f2, ++ 0x075af89a, ++ 0x05e3fa1d, ++ 0xf8a60766, ++ 0xf7ac09f2, ++ 0x0388f67a, ++ 0xfa1dfbd6, ++ 0x0bdbfc59, ++ 0x0854f760, ++ 0x00fa0705, ++ 0xfa58fa58, ++ 0xf8f0fe00, ++ 0x0448073d, ++ 0xfdc9fe46, ++ 0xf9910258, ++ 0x089d0407, ++ 0xfd5cf71a, ++ 0x02affde0, ++ 0x083e0496, ++ 0xff5a0740, ++ 0xff7afd97, ++ 0x00fe01f1, ++ 0x0009082e, ++ 0xfa94ff75, ++ 0xfecdf8ea, ++ 0xffb0f693, ++ 0xfd2cfa58, ++ 0x0433ff16, ++ 0xfba405dd, ++ 0xfa610341, ++ 0x06a606cb, ++ 0x0039fd2d, ++ 0x0677fa97, ++ 0x01fa05e0, ++ 0xf896003e, ++ 0x075a068b, ++ 0x012cfc3e, ++ 0xfa23f98d, ++ 0xfc7cfd43, ++ 0xff90fc0d, ++ 0x01c10982, ++ 0x00c601d6, ++ 0xfd2cfd2c, ++ 0x01d600c6, ++ 0x098201c1, ++ 0xfc0dff90, ++ 0xfd43fc7c, ++ 0xf98dfa23, ++ 0xfc3e012c, ++ 0x068b075a, ++ 0x003ef896, ++ 0x05e001fa, ++ 0xfa970677, ++ 0xfd2d0039, ++ 0x06cb06a6, ++ 0x0341fa61, ++ 0x05ddfba4, ++ 0xff160433, ++ 0xfa58fd2c, ++ 0xf693ffb0, ++ 0xf8eafecd, ++ 0xff75fa94, ++ 0x082e0009, ++ 0x01f100fe, ++ 0xfd97ff7a, ++ 0x0740ff5a, ++ 0x0496083e, ++ 0xfde002af, ++ 0xf71afd5c, ++ 0x0407089d, ++ 0x0258f991, ++ 0xfe46fdc9, ++ 0x073d0448, ++ 0xfe00f8f0, ++ 0xfd2cfd2c, ++ 0xfce00500, ++ 0xfc09fddc, ++ 0xfe680157, ++ 0x04c70571, ++ 0xfc3aff21, ++ 0xfcd70228, ++ 0x056d0277, ++ 0x0200fe00, ++ 0x0022f927, ++ 0xfe3c032b, ++ 0xfc44ff3c, ++ 0x03e9fbdb, ++ 0x04570313, ++ 0x04c9ff5c, ++ 0x000d03b8, ++ 0xfa580000, ++ 0xfbe900d2, ++ 0xf9d0fe0b, ++ 0x0125fdf9, ++ 0x042501bf, ++ 0x0328fa2b, ++ 0xffa902f0, ++ 0xfa250157, ++ 0x0200fe00, ++ 0x03740438, ++ 0xff0405fd, ++ 0x030cfe52, ++ 0x0037fb39, ++ 0xff6904c5, ++ 0x04f8fd23, ++ 0xfd31fc1b, ++ 0xfd2cfd2c, ++ 0xfc1bfd31, ++ 0xfd2304f8, ++ 0x04c5ff69, ++ 0xfb390037, ++ 0xfe52030c, ++ 0x05fdff04, ++ 0x04380374, ++ 0xfe000200, ++ 0x0157fa25, ++ 0x02f0ffa9, ++ 0xfa2b0328, ++ 0x01bf0425, ++ 0xfdf90125, ++ 0xfe0bf9d0, ++ 0x00d2fbe9, ++ 0x0000fa58, ++ 0x03b8000d, ++ 0xff5c04c9, ++ 0x03130457, ++ 0xfbdb03e9, ++ 0xff3cfc44, ++ 0x032bfe3c, ++ 0xf9270022, ++ 0xfe000200, ++ 0x0277056d, ++ 0x0228fcd7, ++ 0xff21fc3a, ++ 0x057104c7, ++ 0x0157fe68, ++ 0xfddcfc09, ++ 0x0500fce0, ++ 0xfd2cfd2c, ++ 0x0500fce0, ++ 0xfddcfc09, ++ 0x0157fe68, ++ 0x057104c7, ++ 0xff21fc3a, ++ 0x0228fcd7, ++ 0x0277056d, ++ 0xfe000200, ++ 0xf9270022, ++ 0x032bfe3c, ++ 0xff3cfc44, ++ 0xfbdb03e9, ++ 0x03130457, ++ 0xff5c04c9, ++ 0x03b8000d, ++ 0x0000fa58, ++ 0x00d2fbe9, ++ 0xfe0bf9d0, ++ 0xfdf90125, ++ 0x01bf0425, ++ 0xfa2b0328, ++ 0x02f0ffa9, ++ 0x0157fa25, ++ 0xfe000200, ++ 0x04380374, ++ 0x05fdff04, ++ 0xfe52030c, ++ 0xfb390037, ++ 0x04c5ff69, ++ 0xfd2304f8, ++ 0xfc1bfd31, ++ 0xfd2cfd2c, ++ 0xfd31fc1b, ++ 0x04f8fd23, ++ 0xff6904c5, ++ 0x0037fb39, ++ 0x030cfe52, ++ 0xff0405fd, ++ 0x03740438, ++ 0x0200fe00, ++ 0xfa250157, ++ 0xffa902f0, ++ 0x0328fa2b, ++ 0x042501bf, ++ 0x0125fdf9, ++ 0xf9d0fe0b, ++ 0xfbe900d2, ++ 0xfa580000, ++ 0x000d03b8, ++ 0x04c9ff5c, ++ 0x04570313, ++ 0x03e9fbdb, ++ 0xfc44ff3c, ++ 0xfe3c032b, ++ 0x0022f927, ++ 0x0200fe00, ++ 0x056d0277, ++ 0xfcd70228, ++ 0xfc3aff21, ++ 0x04c70571, ++ 0xfe680157, ++ 0xfc09fddc, ++ 0xfce00500, ++ 0x05a80000, ++ 0xff1006be, ++ 0x0800084a, ++ 0xf49cfc7e, ++ 0xfa580400, ++ 0xfc9cf6da, ++ 0xf800f672, ++ 0x0710071c, ++ 0x05a805a8, ++ 0xf8f0f8e4, ++ 0xf800f672, ++ 0x03640926, ++ 0xfa580400, ++ 0x0b640382, ++ 0x0800084a, ++ 0x00f0f942, ++ 0x05a80000, ++ 0xff10f942, ++ 0x0800f7b6, ++ 0xf49c0382, ++ 0xfa58fc00, ++ 0xfc9c0926, ++ 0xf800098e, ++ 0x0710f8e4, ++ 0x05a8fa58, ++ 0xf8f0071c, ++ 0xf800098e, ++ 0x0364f6da, ++ 0xfa58fc00, ++ 0x0b64fc7e, ++ 0x0800f7b6, ++ 0x00f006be, ++ 0x05a80000, ++ 0xff1006be, ++ 0x0800084a, ++ 0xf49cfc7e, ++ 0xfa580400, ++ 0xfc9cf6da, ++ 0xf800f672, ++ 0x0710071c, ++ 0x05a805a8, ++ 0xf8f0f8e4, ++ 0xf800f672, ++ 0x03640926, ++ 0xfa580400, ++ 0x0b640382, ++ 0x0800084a, ++ 0x00f0f942, ++ 0x05a80000, ++ 0xff10f942, ++ 0x0800f7b6, ++ 0xf49c0382, ++ 0xfa58fc00, ++ 0xfc9c0926, ++ 0xf800098e, ++ 0x0710f8e4, ++ 0x05a8fa58, ++ 0xf8f0071c, ++ 0xf800098e, ++ 0x0364f6da, ++ 0xfa58fc00, ++ 0x0b64fc7e, ++ 0x0800f7b6, ++ 0x00f006be, ++}; ++ ++static const u32 intlv_tbl_rev0[] = { ++ 0x00802070, ++ 0x0671188d, ++ 0x0a60192c, ++ 0x0a300e46, ++ 0x00c1188d, ++ 0x080024d2, ++ 0x00000070, ++}; ++ ++static const u16 pilot_tbl_rev0[] = { ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0xff0a, ++ 0xff82, ++ 0xffa0, ++ 0xff28, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xff82, ++ 0xffa0, ++ 0xff28, ++ 0xff0a, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xf83f, ++ 0xfa1f, ++ 0xfa97, ++ 0xfab5, ++ 0xf2bd, ++ 0xf0bf, ++ 0xffff, ++ 0xffff, ++ 0xf017, ++ 0xf815, ++ 0xf215, ++ 0xf095, ++ 0xf035, ++ 0xf01d, ++ 0xffff, ++ 0xffff, ++ 0xff08, ++ 0xff02, ++ 0xff80, ++ 0xff20, ++ 0xff08, ++ 0xff02, ++ 0xff80, ++ 0xff20, ++ 0xf01f, ++ 0xf817, ++ 0xfa15, ++ 0xf295, ++ 0xf0b5, ++ 0xf03d, ++ 0xffff, ++ 0xffff, ++ 0xf82a, ++ 0xfa0a, ++ 0xfa82, ++ 0xfaa0, ++ 0xf2a8, ++ 0xf0aa, ++ 0xffff, ++ 0xffff, ++ 0xf002, ++ 0xf800, ++ 0xf200, ++ 0xf080, ++ 0xf020, ++ 0xf008, ++ 0xffff, ++ 0xffff, ++ 0xf00a, ++ 0xf802, ++ 0xfa00, ++ 0xf280, ++ 0xf0a0, ++ 0xf028, ++ 0xffff, ++ 0xffff, ++}; ++ ++static const u32 pltlut_tbl_rev0[] = { ++ 0x76540123, ++ 0x62407351, ++ 0x76543201, ++ 0x76540213, ++ 0x76540123, ++ 0x76430521, ++}; ++ ++static const u32 tdi_tbl20_ant0_rev0[] = { ++ 0x00091226, ++ 0x000a1429, ++ 0x000b56ad, ++ 0x000c58b0, ++ 0x000d5ab3, ++ 0x000e9cb6, ++ 0x000f9eba, ++ 0x0000c13d, ++ 0x00020301, ++ 0x00030504, ++ 0x00040708, ++ 0x0005090b, ++ 0x00064b8e, ++ 0x00095291, ++ 0x000a5494, ++ 0x000b9718, ++ 0x000c9927, ++ 0x000d9b2a, ++ 0x000edd2e, ++ 0x000fdf31, ++ 0x000101b4, ++ 0x000243b7, ++ 0x000345bb, ++ 0x000447be, ++ 0x00058982, ++ 0x00068c05, ++ 0x00099309, ++ 0x000a950c, ++ 0x000bd78f, ++ 0x000cd992, ++ 0x000ddb96, ++ 0x000f1d99, ++ 0x00005fa8, ++ 0x0001422c, ++ 0x0002842f, ++ 0x00038632, ++ 0x00048835, ++ 0x0005ca38, ++ 0x0006ccbc, ++ 0x0009d3bf, ++ 0x000b1603, ++ 0x000c1806, ++ 0x000d1a0a, ++ 0x000e1c0d, ++ 0x000f5e10, ++ 0x00008093, ++ 0x00018297, ++ 0x0002c49a, ++ 0x0003c680, ++ 0x0004c880, ++ 0x00060b00, ++ 0x00070d00, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl20_ant1_rev0[] = { ++ 0x00014b26, ++ 0x00028d29, ++ 0x000393ad, ++ 0x00049630, ++ 0x0005d833, ++ 0x0006da36, ++ 0x00099c3a, ++ 0x000a9e3d, ++ 0x000bc081, ++ 0x000cc284, ++ 0x000dc488, ++ 0x000f068b, ++ 0x0000488e, ++ 0x00018b91, ++ 0x0002d214, ++ 0x0003d418, ++ 0x0004d6a7, ++ 0x000618aa, ++ 0x00071aae, ++ 0x0009dcb1, ++ 0x000b1eb4, ++ 0x000c0137, ++ 0x000d033b, ++ 0x000e053e, ++ 0x000f4702, ++ 0x00008905, ++ 0x00020c09, ++ 0x0003128c, ++ 0x0004148f, ++ 0x00051712, ++ 0x00065916, ++ 0x00091b19, ++ 0x000a1d28, ++ 0x000b5f2c, ++ 0x000c41af, ++ 0x000d43b2, ++ 0x000e85b5, ++ 0x000f87b8, ++ 0x0000c9bc, ++ 0x00024cbf, ++ 0x00035303, ++ 0x00045506, ++ 0x0005978a, ++ 0x0006998d, ++ 0x00095b90, ++ 0x000a5d93, ++ 0x000b9f97, ++ 0x000c821a, ++ 0x000d8400, ++ 0x000ec600, ++ 0x000fc800, ++ 0x00010a00, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl40_ant0_rev0[] = { ++ 0x0011a346, ++ 0x00136ccf, ++ 0x0014f5d9, ++ 0x001641e2, ++ 0x0017cb6b, ++ 0x00195475, ++ 0x001b2383, ++ 0x001cad0c, ++ 0x001e7616, ++ 0x0000821f, ++ 0x00020ba8, ++ 0x0003d4b2, ++ 0x00056447, ++ 0x00072dd0, ++ 0x0008b6da, ++ 0x000a02e3, ++ 0x000b8c6c, ++ 0x000d15f6, ++ 0x0011e484, ++ 0x0013ae0d, ++ 0x00153717, ++ 0x00168320, ++ 0x00180ca9, ++ 0x00199633, ++ 0x001b6548, ++ 0x001ceed1, ++ 0x001eb7db, ++ 0x0000c3e4, ++ 0x00024d6d, ++ 0x000416f7, ++ 0x0005a585, ++ 0x00076f0f, ++ 0x0008f818, ++ 0x000a4421, ++ 0x000bcdab, ++ 0x000d9734, ++ 0x00122649, ++ 0x0013efd2, ++ 0x001578dc, ++ 0x0016c4e5, ++ 0x00184e6e, ++ 0x001a17f8, ++ 0x001ba686, ++ 0x001d3010, ++ 0x001ef999, ++ 0x00010522, ++ 0x00028eac, ++ 0x00045835, ++ 0x0005e74a, ++ 0x0007b0d3, ++ 0x00093a5d, ++ 0x000a85e6, ++ 0x000c0f6f, ++ 0x000dd8f9, ++ 0x00126787, ++ 0x00143111, ++ 0x0015ba9a, ++ 0x00170623, ++ 0x00188fad, ++ 0x001a5936, ++ 0x001be84b, ++ 0x001db1d4, ++ 0x001f3b5e, ++ 0x000146e7, ++ 0x00031070, ++ 0x000499fa, ++ 0x00062888, ++ 0x0007f212, ++ 0x00097b9b, ++ 0x000ac7a4, ++ 0x000c50ae, ++ 0x000e1a37, ++ 0x0012a94c, ++ 0x001472d5, ++ 0x0015fc5f, ++ 0x00174868, ++ 0x0018d171, ++ 0x001a9afb, ++ 0x001c2989, ++ 0x001df313, ++ 0x001f7c9c, ++ 0x000188a5, ++ 0x000351af, ++ 0x0004db38, ++ 0x0006aa4d, ++ 0x000833d7, ++ 0x0009bd60, ++ 0x000b0969, ++ 0x000c9273, ++ 0x000e5bfc, ++ 0x00132a8a, ++ 0x0014b414, ++ 0x00163d9d, ++ 0x001789a6, ++ 0x001912b0, ++ 0x001adc39, ++ 0x001c6bce, ++ 0x001e34d8, ++ 0x001fbe61, ++ 0x0001ca6a, ++ 0x00039374, ++ 0x00051cfd, ++ 0x0006ec0b, ++ 0x00087515, ++ 0x0009fe9e, ++ 0x000b4aa7, ++ 0x000cd3b1, ++ 0x000e9d3a, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl40_ant1_rev0[] = { ++ 0x001edb36, ++ 0x000129ca, ++ 0x0002b353, ++ 0x00047cdd, ++ 0x0005c8e6, ++ 0x000791ef, ++ 0x00091bf9, ++ 0x000aaa07, ++ 0x000c3391, ++ 0x000dfd1a, ++ 0x00120923, ++ 0x0013d22d, ++ 0x00155c37, ++ 0x0016eacb, ++ 0x00187454, ++ 0x001a3dde, ++ 0x001b89e7, ++ 0x001d12f0, ++ 0x001f1cfa, ++ 0x00016b88, ++ 0x00033492, ++ 0x0004be1b, ++ 0x00060a24, ++ 0x0007d32e, ++ 0x00095d38, ++ 0x000aec4c, ++ 0x000c7555, ++ 0x000e3edf, ++ 0x00124ae8, ++ 0x001413f1, ++ 0x0015a37b, ++ 0x00172c89, ++ 0x0018b593, ++ 0x001a419c, ++ 0x001bcb25, ++ 0x001d942f, ++ 0x001f63b9, ++ 0x0001ad4d, ++ 0x00037657, ++ 0x0004c260, ++ 0x00068be9, ++ 0x000814f3, ++ 0x0009a47c, ++ 0x000b2d8a, ++ 0x000cb694, ++ 0x000e429d, ++ 0x00128c26, ++ 0x001455b0, ++ 0x0015e4ba, ++ 0x00176e4e, ++ 0x0018f758, ++ 0x001a8361, ++ 0x001c0cea, ++ 0x001dd674, ++ 0x001fa57d, ++ 0x0001ee8b, ++ 0x0003b795, ++ 0x0005039e, ++ 0x0006cd27, ++ 0x000856b1, ++ 0x0009e5c6, ++ 0x000b6f4f, ++ 0x000cf859, ++ 0x000e8462, ++ 0x00130deb, ++ 0x00149775, ++ 0x00162603, ++ 0x0017af8c, ++ 0x00193896, ++ 0x001ac49f, ++ 0x001c4e28, ++ 0x001e17b2, ++ 0x0000a6c7, ++ 0x00023050, ++ 0x0003f9da, ++ 0x00054563, ++ 0x00070eec, ++ 0x00089876, ++ 0x000a2704, ++ 0x000bb08d, ++ 0x000d3a17, ++ 0x001185a0, ++ 0x00134f29, ++ 0x0014d8b3, ++ 0x001667c8, ++ 0x0017f151, ++ 0x00197adb, ++ 0x001b0664, ++ 0x001c8fed, ++ 0x001e5977, ++ 0x0000e805, ++ 0x0002718f, ++ 0x00043b18, ++ 0x000586a1, ++ 0x0007502b, ++ 0x0008d9b4, ++ 0x000a68c9, ++ 0x000bf252, ++ 0x000dbbdc, ++ 0x0011c7e5, ++ 0x001390ee, ++ 0x00151a78, ++ 0x0016a906, ++ 0x00183290, ++ 0x0019bc19, ++ 0x001b4822, ++ 0x001cd12c, ++ 0x001e9ab5, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u16 bdi_tbl_rev0[] = { ++ 0x0070, ++ 0x0126, ++ 0x012c, ++ 0x0246, ++ 0x048d, ++ 0x04d2, ++}; ++ ++static const u32 chanest_tbl_rev0[] = { ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++}; ++ ++static const u8 mcs_tbl_rev0[] = { ++ 0x00, ++ 0x08, ++ 0x0a, ++ 0x10, ++ 0x12, ++ 0x19, ++ 0x1a, ++ 0x1c, ++ 0x40, ++ 0x48, ++ 0x4a, ++ 0x50, ++ 0x52, ++ 0x59, ++ 0x5a, ++ 0x5c, ++ 0x80, ++ 0x88, ++ 0x8a, ++ 0x90, ++ 0x92, ++ 0x99, ++ 0x9a, ++ 0x9c, ++ 0xc0, ++ 0xc8, ++ 0xca, ++ 0xd0, ++ 0xd2, ++ 0xd9, ++ 0xda, ++ 0xdc, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x01, ++ 0x02, ++ 0x04, ++ 0x08, ++ 0x09, ++ 0x0a, ++ 0x0c, ++ 0x10, ++ 0x11, ++ 0x12, ++ 0x14, ++ 0x18, ++ 0x19, ++ 0x1a, ++ 0x1c, ++ 0x20, ++ 0x21, ++ 0x22, ++ 0x24, ++ 0x40, ++ 0x41, ++ 0x42, ++ 0x44, ++ 0x48, ++ 0x49, ++ 0x4a, ++ 0x4c, ++ 0x50, ++ 0x51, ++ 0x52, ++ 0x54, ++ 0x58, ++ 0x59, ++ 0x5a, ++ 0x5c, ++ 0x60, ++ 0x61, ++ 0x62, ++ 0x64, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++}; ++ ++static const u32 noise_var_tbl0_rev0[] = { ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++}; ++ ++static const u32 noise_var_tbl1_rev0[] = { ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++}; ++ ++static const u8 est_pwr_lut_core0_rev0[] = { ++ 0x50, ++ 0x4f, ++ 0x4e, ++ 0x4d, ++ 0x4c, ++ 0x4b, ++ 0x4a, ++ 0x49, ++ 0x48, ++ 0x47, ++ 0x46, ++ 0x45, ++ 0x44, ++ 0x43, ++ 0x42, ++ 0x41, ++ 0x40, ++ 0x3f, ++ 0x3e, ++ 0x3d, ++ 0x3c, ++ 0x3b, ++ 0x3a, ++ 0x39, ++ 0x38, ++ 0x37, ++ 0x36, ++ 0x35, ++ 0x34, ++ 0x33, ++ 0x32, ++ 0x31, ++ 0x30, ++ 0x2f, ++ 0x2e, ++ 0x2d, ++ 0x2c, ++ 0x2b, ++ 0x2a, ++ 0x29, ++ 0x28, ++ 0x27, ++ 0x26, ++ 0x25, ++ 0x24, ++ 0x23, ++ 0x22, ++ 0x21, ++ 0x20, ++ 0x1f, ++ 0x1e, ++ 0x1d, ++ 0x1c, ++ 0x1b, ++ 0x1a, ++ 0x19, ++ 0x18, ++ 0x17, ++ 0x16, ++ 0x15, ++ 0x14, ++ 0x13, ++ 0x12, ++ 0x11, ++}; ++ ++static const u8 est_pwr_lut_core1_rev0[] = { ++ 0x50, ++ 0x4f, ++ 0x4e, ++ 0x4d, ++ 0x4c, ++ 0x4b, ++ 0x4a, ++ 0x49, ++ 0x48, ++ 0x47, ++ 0x46, ++ 0x45, ++ 0x44, ++ 0x43, ++ 0x42, ++ 0x41, ++ 0x40, ++ 0x3f, ++ 0x3e, ++ 0x3d, ++ 0x3c, ++ 0x3b, ++ 0x3a, ++ 0x39, ++ 0x38, ++ 0x37, ++ 0x36, ++ 0x35, ++ 0x34, ++ 0x33, ++ 0x32, ++ 0x31, ++ 0x30, ++ 0x2f, ++ 0x2e, ++ 0x2d, ++ 0x2c, ++ 0x2b, ++ 0x2a, ++ 0x29, ++ 0x28, ++ 0x27, ++ 0x26, ++ 0x25, ++ 0x24, ++ 0x23, ++ 0x22, ++ 0x21, ++ 0x20, ++ 0x1f, ++ 0x1e, ++ 0x1d, ++ 0x1c, ++ 0x1b, ++ 0x1a, ++ 0x19, ++ 0x18, ++ 0x17, ++ 0x16, ++ 0x15, ++ 0x14, ++ 0x13, ++ 0x12, ++ 0x11, ++}; ++ ++static const u8 adj_pwr_lut_core0_rev0[] = { ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++}; ++ ++static const u8 adj_pwr_lut_core1_rev0[] = { ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++}; ++ ++static const u32 gainctrl_lut_core0_rev0[] = { ++ 0x03cc2b44, ++ 0x03cc2b42, ++ 0x03cc2b40, ++ 0x03cc2b3e, ++ 0x03cc2b3d, ++ 0x03cc2b3b, ++ 0x03c82b44, ++ 0x03c82b42, ++ 0x03c82b40, ++ 0x03c82b3e, ++ 0x03c82b3d, ++ 0x03c82b3b, ++ 0x03c82b39, ++ 0x03c82b38, ++ 0x03c82b36, ++ 0x03c82b34, ++ 0x03c42b44, ++ 0x03c42b42, ++ 0x03c42b40, ++ 0x03c42b3e, ++ 0x03c42b3d, ++ 0x03c42b3b, ++ 0x03c42b39, ++ 0x03c42b38, ++ 0x03c42b36, ++ 0x03c42b34, ++ 0x03c42b33, ++ 0x03c42b32, ++ 0x03c42b30, ++ 0x03c42b2f, ++ 0x03c42b2d, ++ 0x03c02b44, ++ 0x03c02b42, ++ 0x03c02b40, ++ 0x03c02b3e, ++ 0x03c02b3d, ++ 0x03c02b3b, ++ 0x03c02b39, ++ 0x03c02b38, ++ 0x03c02b36, ++ 0x03c02b34, ++ 0x03b02b44, ++ 0x03b02b42, ++ 0x03b02b40, ++ 0x03b02b3e, ++ 0x03b02b3d, ++ 0x03b02b3b, ++ 0x03b02b39, ++ 0x03b02b38, ++ 0x03b02b36, ++ 0x03b02b34, ++ 0x03b02b33, ++ 0x03b02b32, ++ 0x03b02b30, ++ 0x03b02b2f, ++ 0x03b02b2d, ++ 0x03a02b44, ++ 0x03a02b42, ++ 0x03a02b40, ++ 0x03a02b3e, ++ 0x03a02b3d, ++ 0x03a02b3b, ++ 0x03a02b39, ++ 0x03a02b38, ++ 0x03a02b36, ++ 0x03a02b34, ++ 0x03902b44, ++ 0x03902b42, ++ 0x03902b40, ++ 0x03902b3e, ++ 0x03902b3d, ++ 0x03902b3b, ++ 0x03902b39, ++ 0x03902b38, ++ 0x03902b36, ++ 0x03902b34, ++ 0x03902b33, ++ 0x03902b32, ++ 0x03902b30, ++ 0x03802b44, ++ 0x03802b42, ++ 0x03802b40, ++ 0x03802b3e, ++ 0x03802b3d, ++ 0x03802b3b, ++ 0x03802b39, ++ 0x03802b38, ++ 0x03802b36, ++ 0x03802b34, ++ 0x03802b33, ++ 0x03802b32, ++ 0x03802b30, ++ 0x03802b2f, ++ 0x03802b2d, ++ 0x03802b2c, ++ 0x03802b2b, ++ 0x03802b2a, ++ 0x03802b29, ++ 0x03802b27, ++ 0x03802b26, ++ 0x03802b25, ++ 0x03802b24, ++ 0x03802b23, ++ 0x03802b22, ++ 0x03802b21, ++ 0x03802b20, ++ 0x03802b1f, ++ 0x03802b1e, ++ 0x03802b1e, ++ 0x03802b1d, ++ 0x03802b1c, ++ 0x03802b1b, ++ 0x03802b1a, ++ 0x03802b1a, ++ 0x03802b19, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x00002b00, ++}; ++ ++static const u32 gainctrl_lut_core1_rev0[] = { ++ 0x03cc2b44, ++ 0x03cc2b42, ++ 0x03cc2b40, ++ 0x03cc2b3e, ++ 0x03cc2b3d, ++ 0x03cc2b3b, ++ 0x03c82b44, ++ 0x03c82b42, ++ 0x03c82b40, ++ 0x03c82b3e, ++ 0x03c82b3d, ++ 0x03c82b3b, ++ 0x03c82b39, ++ 0x03c82b38, ++ 0x03c82b36, ++ 0x03c82b34, ++ 0x03c42b44, ++ 0x03c42b42, ++ 0x03c42b40, ++ 0x03c42b3e, ++ 0x03c42b3d, ++ 0x03c42b3b, ++ 0x03c42b39, ++ 0x03c42b38, ++ 0x03c42b36, ++ 0x03c42b34, ++ 0x03c42b33, ++ 0x03c42b32, ++ 0x03c42b30, ++ 0x03c42b2f, ++ 0x03c42b2d, ++ 0x03c02b44, ++ 0x03c02b42, ++ 0x03c02b40, ++ 0x03c02b3e, ++ 0x03c02b3d, ++ 0x03c02b3b, ++ 0x03c02b39, ++ 0x03c02b38, ++ 0x03c02b36, ++ 0x03c02b34, ++ 0x03b02b44, ++ 0x03b02b42, ++ 0x03b02b40, ++ 0x03b02b3e, ++ 0x03b02b3d, ++ 0x03b02b3b, ++ 0x03b02b39, ++ 0x03b02b38, ++ 0x03b02b36, ++ 0x03b02b34, ++ 0x03b02b33, ++ 0x03b02b32, ++ 0x03b02b30, ++ 0x03b02b2f, ++ 0x03b02b2d, ++ 0x03a02b44, ++ 0x03a02b42, ++ 0x03a02b40, ++ 0x03a02b3e, ++ 0x03a02b3d, ++ 0x03a02b3b, ++ 0x03a02b39, ++ 0x03a02b38, ++ 0x03a02b36, ++ 0x03a02b34, ++ 0x03902b44, ++ 0x03902b42, ++ 0x03902b40, ++ 0x03902b3e, ++ 0x03902b3d, ++ 0x03902b3b, ++ 0x03902b39, ++ 0x03902b38, ++ 0x03902b36, ++ 0x03902b34, ++ 0x03902b33, ++ 0x03902b32, ++ 0x03902b30, ++ 0x03802b44, ++ 0x03802b42, ++ 0x03802b40, ++ 0x03802b3e, ++ 0x03802b3d, ++ 0x03802b3b, ++ 0x03802b39, ++ 0x03802b38, ++ 0x03802b36, ++ 0x03802b34, ++ 0x03802b33, ++ 0x03802b32, ++ 0x03802b30, ++ 0x03802b2f, ++ 0x03802b2d, ++ 0x03802b2c, ++ 0x03802b2b, ++ 0x03802b2a, ++ 0x03802b29, ++ 0x03802b27, ++ 0x03802b26, ++ 0x03802b25, ++ 0x03802b24, ++ 0x03802b23, ++ 0x03802b22, ++ 0x03802b21, ++ 0x03802b20, ++ 0x03802b1f, ++ 0x03802b1e, ++ 0x03802b1e, ++ 0x03802b1d, ++ 0x03802b1c, ++ 0x03802b1b, ++ 0x03802b1a, ++ 0x03802b1a, ++ 0x03802b19, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x03802b18, ++ 0x00002b00, ++}; ++ ++static const u32 iq_lut_core0_rev0[] = { ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++}; ++ ++static const u32 iq_lut_core1_rev0[] = { ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++ 0x0000007f, ++}; ++ ++static const u16 loft_lut_core0_rev0[] = { ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++}; ++ ++static const u16 loft_lut_core1_rev0[] = { ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++ 0x0000, ++ 0x0101, ++ 0x0002, ++ 0x0103, ++}; ++ ++const struct phytbl_info mimophytbl_info_rev0_volatile[] = { ++ {&bdi_tbl_rev0, sizeof(bdi_tbl_rev0) / sizeof(bdi_tbl_rev0[0]), 21, 0, ++ 16} ++ , ++ {&pltlut_tbl_rev0, sizeof(pltlut_tbl_rev0) / sizeof(pltlut_tbl_rev0[0]), ++ 20, 0, 32} ++ , ++ {&gainctrl_lut_core0_rev0, ++ sizeof(gainctrl_lut_core0_rev0) / sizeof(gainctrl_lut_core0_rev0[0]), ++ 26, 192, 32} ++ , ++ {&gainctrl_lut_core1_rev0, ++ sizeof(gainctrl_lut_core1_rev0) / sizeof(gainctrl_lut_core1_rev0[0]), ++ 27, 192, 32} ++ , ++ ++ {&est_pwr_lut_core0_rev0, ++ sizeof(est_pwr_lut_core0_rev0) / sizeof(est_pwr_lut_core0_rev0[0]), 26, ++ 0, 8} ++ , ++ {&est_pwr_lut_core1_rev0, ++ sizeof(est_pwr_lut_core1_rev0) / sizeof(est_pwr_lut_core1_rev0[0]), 27, ++ 0, 8} ++ , ++ {&adj_pwr_lut_core0_rev0, ++ sizeof(adj_pwr_lut_core0_rev0) / sizeof(adj_pwr_lut_core0_rev0[0]), 26, ++ 64, 8} ++ , ++ {&adj_pwr_lut_core1_rev0, ++ sizeof(adj_pwr_lut_core1_rev0) / sizeof(adj_pwr_lut_core1_rev0[0]), 27, ++ 64, 8} ++ , ++ {&iq_lut_core0_rev0, ++ sizeof(iq_lut_core0_rev0) / sizeof(iq_lut_core0_rev0[0]), 26, 320, 32} ++ , ++ {&iq_lut_core1_rev0, ++ sizeof(iq_lut_core1_rev0) / sizeof(iq_lut_core1_rev0[0]), 27, 320, 32} ++ , ++ {&loft_lut_core0_rev0, ++ sizeof(loft_lut_core0_rev0) / sizeof(loft_lut_core0_rev0[0]), 26, 448, ++ 16} ++ , ++ {&loft_lut_core1_rev0, ++ sizeof(loft_lut_core1_rev0) / sizeof(loft_lut_core1_rev0[0]), 27, 448, ++ 16} ++ , ++}; ++ ++const struct phytbl_info mimophytbl_info_rev0[] = { ++ {&frame_struct_rev0, ++ sizeof(frame_struct_rev0) / sizeof(frame_struct_rev0[0]), 10, 0, 32} ++ , ++ {&frame_lut_rev0, sizeof(frame_lut_rev0) / sizeof(frame_lut_rev0[0]), ++ 24, 0, 8} ++ , ++ {&tmap_tbl_rev0, sizeof(tmap_tbl_rev0) / sizeof(tmap_tbl_rev0[0]), 12, ++ 0, 32} ++ , ++ {&tdtrn_tbl_rev0, sizeof(tdtrn_tbl_rev0) / sizeof(tdtrn_tbl_rev0[0]), ++ 14, 0, 32} ++ , ++ {&intlv_tbl_rev0, sizeof(intlv_tbl_rev0) / sizeof(intlv_tbl_rev0[0]), ++ 13, 0, 32} ++ , ++ {&pilot_tbl_rev0, sizeof(pilot_tbl_rev0) / sizeof(pilot_tbl_rev0[0]), ++ 11, 0, 16} ++ , ++ {&tdi_tbl20_ant0_rev0, ++ sizeof(tdi_tbl20_ant0_rev0) / sizeof(tdi_tbl20_ant0_rev0[0]), 19, 128, ++ 32} ++ , ++ {&tdi_tbl20_ant1_rev0, ++ sizeof(tdi_tbl20_ant1_rev0) / sizeof(tdi_tbl20_ant1_rev0[0]), 19, 256, ++ 32} ++ , ++ {&tdi_tbl40_ant0_rev0, ++ sizeof(tdi_tbl40_ant0_rev0) / sizeof(tdi_tbl40_ant0_rev0[0]), 19, 640, ++ 32} ++ , ++ {&tdi_tbl40_ant1_rev0, ++ sizeof(tdi_tbl40_ant1_rev0) / sizeof(tdi_tbl40_ant1_rev0[0]), 19, 768, ++ 32} ++ , ++ {&chanest_tbl_rev0, ++ sizeof(chanest_tbl_rev0) / sizeof(chanest_tbl_rev0[0]), 22, 0, 32} ++ , ++ {&mcs_tbl_rev0, sizeof(mcs_tbl_rev0) / sizeof(mcs_tbl_rev0[0]), 18, 0, ++ 8} ++ , ++ {&noise_var_tbl0_rev0, ++ sizeof(noise_var_tbl0_rev0) / sizeof(noise_var_tbl0_rev0[0]), 16, 0, ++ 32} ++ , ++ {&noise_var_tbl1_rev0, ++ sizeof(noise_var_tbl1_rev0) / sizeof(noise_var_tbl1_rev0[0]), 16, 128, ++ 32} ++ , ++}; ++ ++const u32 mimophytbl_info_sz_rev0 = ++ sizeof(mimophytbl_info_rev0) / sizeof(mimophytbl_info_rev0[0]); ++const u32 mimophytbl_info_sz_rev0_volatile = ++ sizeof(mimophytbl_info_rev0_volatile) / ++ sizeof(mimophytbl_info_rev0_volatile[0]); ++ ++static const u16 ant_swctrl_tbl_rev3[] = { ++ 0x0082, ++ 0x0082, ++ 0x0211, ++ 0x0222, ++ 0x0328, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0144, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0188, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0082, ++ 0x0082, ++ 0x0211, ++ 0x0222, ++ 0x0328, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0144, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0188, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u16 ant_swctrl_tbl_rev3_1[] = { ++ 0x0022, ++ 0x0022, ++ 0x0011, ++ 0x0022, ++ 0x0022, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0011, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0022, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0022, ++ 0x0022, ++ 0x0011, ++ 0x0022, ++ 0x0022, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0011, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0022, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u16 ant_swctrl_tbl_rev3_2[] = { ++ 0x0088, ++ 0x0088, ++ 0x0044, ++ 0x0088, ++ 0x0088, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0044, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0088, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0088, ++ 0x0088, ++ 0x0044, ++ 0x0088, ++ 0x0088, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0044, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0088, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u16 ant_swctrl_tbl_rev3_3[] = { ++ 0x022, ++ 0x022, ++ 0x011, ++ 0x022, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x011, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x022, ++ 0x000, ++ 0x000, ++ 0x3cc, ++ 0x022, ++ 0x022, ++ 0x011, ++ 0x022, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x011, ++ 0x000, ++ 0x000, ++ 0x000, ++ 0x022, ++ 0x000, ++ 0x000, ++ 0x3cc ++}; ++ ++static const u32 frame_struct_rev3[] = { ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x09804506, ++ 0x00100030, ++ 0x09804507, ++ 0x00100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a0c, ++ 0x00100004, ++ 0x01000a0d, ++ 0x00100024, ++ 0x0980450e, ++ 0x00100034, ++ 0x0980450f, ++ 0x00100034, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a04, ++ 0x00100000, ++ 0x11008a05, ++ 0x00100020, ++ 0x1980c506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x01800504, ++ 0x00100030, ++ 0x11808505, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000a04, ++ 0x00100000, ++ 0x11008a05, ++ 0x00100020, ++ 0x21810506, ++ 0x00100030, ++ 0x21810506, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x1980c50e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x0180050c, ++ 0x00100038, ++ 0x1180850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x1980c506, ++ 0x00100030, ++ 0x1980c506, ++ 0x00100030, ++ 0x11808504, ++ 0x00100030, ++ 0x3981ca05, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x10008a04, ++ 0x00100000, ++ 0x3981ca05, ++ 0x00100030, ++ 0x1980c506, ++ 0x00100030, ++ 0x29814507, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a0c, ++ 0x00100008, ++ 0x01000a0d, ++ 0x00100028, ++ 0x1980c50e, ++ 0x00100038, ++ 0x1980c50e, ++ 0x00100038, ++ 0x1180850c, ++ 0x00100038, ++ 0x3981ca0d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x10008a0c, ++ 0x00100008, ++ 0x3981ca0d, ++ 0x00100038, ++ 0x1980c50e, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x02001405, ++ 0x00100040, ++ 0x0b004a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x43020a04, ++ 0x00100060, ++ 0x1b00ca05, ++ 0x00100060, ++ 0x23010a07, ++ 0x01500060, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x13008a06, ++ 0x01900060, ++ 0x13008a06, ++ 0x01900060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x0200140d, ++ 0x00100050, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x50029404, ++ 0x00100000, ++ 0x32019405, ++ 0x00100040, ++ 0x0b004a06, ++ 0x01900060, ++ 0x0b004a06, ++ 0x01900060, ++ 0x5b02ca04, ++ 0x00100060, ++ 0x3b01d405, ++ 0x00100060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x5802d404, ++ 0x00100000, ++ 0x3b01d405, ++ 0x00100060, ++ 0x0b004a06, ++ 0x01900060, ++ 0x23010a07, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x5002940c, ++ 0x00100010, ++ 0x3201940d, ++ 0x00100050, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x5b02ca0c, ++ 0x00100070, ++ 0x3b01d40d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x5802d40c, ++ 0x00100010, ++ 0x3b01d40d, ++ 0x00100070, ++ 0x0b004a0e, ++ 0x01900070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x000f4800, ++ 0x62031405, ++ 0x00100040, ++ 0x53028a06, ++ 0x01900060, ++ 0x53028a07, ++ 0x01900060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x000f4808, ++ 0x6203140d, ++ 0x00100048, ++ 0x53028a0e, ++ 0x01900068, ++ 0x53028a0f, ++ 0x01900068, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100004, ++ 0x11008a0d, ++ 0x00100024, ++ 0x1980c50e, ++ 0x00100034, ++ 0x2181050e, ++ 0x00100034, ++ 0x2181050e, ++ 0x00100034, ++ 0x0180050c, ++ 0x00100038, ++ 0x1180850d, ++ 0x00100038, ++ 0x1181850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000a0c, ++ 0x00100008, ++ 0x11008a0d, ++ 0x00100028, ++ 0x2181050e, ++ 0x00100038, ++ 0x2181050e, ++ 0x00100038, ++ 0x1181850d, ++ 0x00100038, ++ 0x2981450f, ++ 0x01100038, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x08004a04, ++ 0x00100000, ++ 0x01000a05, ++ 0x00100020, ++ 0x0180c506, ++ 0x00100030, ++ 0x0180c506, ++ 0x00100030, ++ 0x2180c50c, ++ 0x00100030, ++ 0x49820a0d, ++ 0x0016a130, ++ 0x41824a0d, ++ 0x0016a130, ++ 0x2981450f, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x2000ca0c, ++ 0x00100000, ++ 0x49820a0d, ++ 0x0016a130, ++ 0x1980c50e, ++ 0x00100030, ++ 0x41824a0d, ++ 0x0016a130, ++ 0x2981450f, ++ 0x01100030, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100008, ++ 0x0200140d, ++ 0x00100048, ++ 0x0b004a0e, ++ 0x01900068, ++ 0x13008a0e, ++ 0x01900068, ++ 0x13008a0e, ++ 0x01900068, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x1b014a0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x13008a0e, ++ 0x01900070, ++ 0x13008a0e, ++ 0x01900070, ++ 0x1b014a0d, ++ 0x00100070, ++ 0x23010a0f, ++ 0x01500070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x50029404, ++ 0x00100000, ++ 0x32019405, ++ 0x00100040, ++ 0x03004a06, ++ 0x01900060, ++ 0x03004a06, ++ 0x01900060, ++ 0x6b030a0c, ++ 0x00100060, ++ 0x4b02140d, ++ 0x0016a160, ++ 0x4302540d, ++ 0x0016a160, ++ 0x23010a0f, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x6b03140c, ++ 0x00100060, ++ 0x4b02140d, ++ 0x0016a160, ++ 0x0b004a0e, ++ 0x01900060, ++ 0x4302540d, ++ 0x0016a160, ++ 0x23010a0f, ++ 0x01500060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x53028a06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x43020a04, ++ 0x00100060, ++ 0x1b00ca05, ++ 0x00100060, ++ 0x53028a07, ++ 0x0190c060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x53028a0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x43020a0c, ++ 0x00100070, ++ 0x1b00ca0d, ++ 0x00100070, ++ 0x53028a0f, ++ 0x0190c070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x40021404, ++ 0x00100000, ++ 0x1a00d405, ++ 0x00100040, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x5b02ca06, ++ 0x01900060, ++ 0x53028a07, ++ 0x0190c060, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x4002140c, ++ 0x00100010, ++ 0x1a00d40d, ++ 0x00100050, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x5b02ca0e, ++ 0x01900070, ++ 0x53028a0f, ++ 0x0190c070, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u16 pilot_tbl_rev3[] = { ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0xff08, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0x80d5, ++ 0xff0a, ++ 0xff82, ++ 0xffa0, ++ 0xff28, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xff82, ++ 0xffa0, ++ 0xff28, ++ 0xff0a, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xffff, ++ 0xf83f, ++ 0xfa1f, ++ 0xfa97, ++ 0xfab5, ++ 0xf2bd, ++ 0xf0bf, ++ 0xffff, ++ 0xffff, ++ 0xf017, ++ 0xf815, ++ 0xf215, ++ 0xf095, ++ 0xf035, ++ 0xf01d, ++ 0xffff, ++ 0xffff, ++ 0xff08, ++ 0xff02, ++ 0xff80, ++ 0xff20, ++ 0xff08, ++ 0xff02, ++ 0xff80, ++ 0xff20, ++ 0xf01f, ++ 0xf817, ++ 0xfa15, ++ 0xf295, ++ 0xf0b5, ++ 0xf03d, ++ 0xffff, ++ 0xffff, ++ 0xf82a, ++ 0xfa0a, ++ 0xfa82, ++ 0xfaa0, ++ 0xf2a8, ++ 0xf0aa, ++ 0xffff, ++ 0xffff, ++ 0xf002, ++ 0xf800, ++ 0xf200, ++ 0xf080, ++ 0xf020, ++ 0xf008, ++ 0xffff, ++ 0xffff, ++ 0xf00a, ++ 0xf802, ++ 0xfa00, ++ 0xf280, ++ 0xf0a0, ++ 0xf028, ++ 0xffff, ++ 0xffff, ++}; ++ ++static const u32 tmap_tbl_rev3[] = { ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x000aa888, ++ 0x88880000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00011111, ++ 0x11110000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00088aaa, ++ 0xaaaa0000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xaaa8aaa0, ++ 0x8aaa8aaa, ++ 0xaa8a8a8a, ++ 0x000aaa88, ++ 0x8aaa0000, ++ 0xaaa8a888, ++ 0x8aa88a8a, ++ 0x8a88a888, ++ 0x08080a00, ++ 0x0a08080a, ++ 0x080a0a08, ++ 0x00080808, ++ 0x080a0000, ++ 0x080a0808, ++ 0x080a0808, ++ 0x0a0a0a08, ++ 0xa0a0a0a0, ++ 0x80a0a080, ++ 0x8080a0a0, ++ 0x00008080, ++ 0x80a00000, ++ 0x80a080a0, ++ 0xa080a0a0, ++ 0x8080a0a0, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x99999000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x22000000, ++ 0x2222b222, ++ 0x22222222, ++ 0x222222b2, ++ 0xb2222220, ++ 0x22222222, ++ 0x22d22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333b333, ++ 0x33333333, ++ 0x333333b3, ++ 0xb3333330, ++ 0x33333333, ++ 0x33d33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x99b99b00, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb99, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x22222200, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0x22222222, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x11111111, ++ 0xf1111111, ++ 0x11111111, ++ 0x11f11111, ++ 0x01111111, ++ 0xbb9bb900, ++ 0xb9b9bb99, ++ 0xb99bbbbb, ++ 0xbbbb9b9b, ++ 0xb9bb99bb, ++ 0xb99999b9, ++ 0xb9b9b99b, ++ 0x00000bbb, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88aa, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x0a888aaa, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00000aaa, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0xbbbbbb00, ++ 0x999bbbbb, ++ 0x9bb99b9b, ++ 0xb9b9b9bb, ++ 0xb9b99bbb, ++ 0xb9b9b9bb, ++ 0xb9bb9b99, ++ 0x00000999, ++ 0x8a000000, ++ 0xaa88a888, ++ 0xa88888aa, ++ 0xa88a8a88, ++ 0xa88aa88a, ++ 0x88a8aaaa, ++ 0xa8aa8aaa, ++ 0x0888a88a, ++ 0x0b0b0b00, ++ 0x090b0b0b, ++ 0x0b090b0b, ++ 0x0909090b, ++ 0x09090b0b, ++ 0x09090b0b, ++ 0x09090b09, ++ 0x00000909, ++ 0x0a000000, ++ 0x0a080808, ++ 0x080a080a, ++ 0x080a0a08, ++ 0x080a080a, ++ 0x0808080a, ++ 0x0a0a0a08, ++ 0x0808080a, ++ 0xb0b0b000, ++ 0x9090b0b0, ++ 0x90b09090, ++ 0xb0b0b090, ++ 0xb0b090b0, ++ 0x90b0b0b0, ++ 0xb0b09090, ++ 0x00000090, ++ 0x80000000, ++ 0xa080a080, ++ 0xa08080a0, ++ 0xa0808080, ++ 0xa080a080, ++ 0x80a0a0a0, ++ 0xa0a080a0, ++ 0x00a0a0a0, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333f333, ++ 0x33333333, ++ 0x333333f3, ++ 0xf3333330, ++ 0x33333333, ++ 0x33f33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x99000000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88888000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x88a88a00, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 intlv_tbl_rev3[] = { ++ 0x00802070, ++ 0x0671188d, ++ 0x0a60192c, ++ 0x0a300e46, ++ 0x00c1188d, ++ 0x080024d2, ++ 0x00000070, ++}; ++ ++static const u32 tdtrn_tbl_rev3[] = { ++ 0x061c061c, ++ 0x0050ee68, ++ 0xf592fe36, ++ 0xfe5212f6, ++ 0x00000c38, ++ 0xfe5212f6, ++ 0xf592fe36, ++ 0x0050ee68, ++ 0x061c061c, ++ 0xee680050, ++ 0xfe36f592, ++ 0x12f6fe52, ++ 0x0c380000, ++ 0x12f6fe52, ++ 0xfe36f592, ++ 0xee680050, ++ 0x061c061c, ++ 0x0050ee68, ++ 0xf592fe36, ++ 0xfe5212f6, ++ 0x00000c38, ++ 0xfe5212f6, ++ 0xf592fe36, ++ 0x0050ee68, ++ 0x061c061c, ++ 0xee680050, ++ 0xfe36f592, ++ 0x12f6fe52, ++ 0x0c380000, ++ 0x12f6fe52, ++ 0xfe36f592, ++ 0xee680050, ++ 0x05e305e3, ++ 0x004def0c, ++ 0xf5f3fe47, ++ 0xfe611246, ++ 0x00000bc7, ++ 0xfe611246, ++ 0xf5f3fe47, ++ 0x004def0c, ++ 0x05e305e3, ++ 0xef0c004d, ++ 0xfe47f5f3, ++ 0x1246fe61, ++ 0x0bc70000, ++ 0x1246fe61, ++ 0xfe47f5f3, ++ 0xef0c004d, ++ 0x05e305e3, ++ 0x004def0c, ++ 0xf5f3fe47, ++ 0xfe611246, ++ 0x00000bc7, ++ 0xfe611246, ++ 0xf5f3fe47, ++ 0x004def0c, ++ 0x05e305e3, ++ 0xef0c004d, ++ 0xfe47f5f3, ++ 0x1246fe61, ++ 0x0bc70000, ++ 0x1246fe61, ++ 0xfe47f5f3, ++ 0xef0c004d, ++ 0xfa58fa58, ++ 0xf895043b, ++ 0xff4c09c0, ++ 0xfbc6ffa8, ++ 0xfb84f384, ++ 0x0798f6f9, ++ 0x05760122, ++ 0x058409f6, ++ 0x0b500000, ++ 0x05b7f542, ++ 0x08860432, ++ 0x06ddfee7, ++ 0xfb84f384, ++ 0xf9d90664, ++ 0xf7e8025c, ++ 0x00fff7bd, ++ 0x05a805a8, ++ 0xf7bd00ff, ++ 0x025cf7e8, ++ 0x0664f9d9, ++ 0xf384fb84, ++ 0xfee706dd, ++ 0x04320886, ++ 0xf54205b7, ++ 0x00000b50, ++ 0x09f60584, ++ 0x01220576, ++ 0xf6f90798, ++ 0xf384fb84, ++ 0xffa8fbc6, ++ 0x09c0ff4c, ++ 0x043bf895, ++ 0x02d402d4, ++ 0x07de0270, ++ 0xfc96079c, ++ 0xf90afe94, ++ 0xfe00ff2c, ++ 0x02d4065d, ++ 0x092a0096, ++ 0x0014fbb8, ++ 0xfd2cfd2c, ++ 0x076afb3c, ++ 0x0096f752, ++ 0xf991fd87, ++ 0xfb2c0200, ++ 0xfeb8f960, ++ 0x08e0fc96, ++ 0x049802a8, ++ 0xfd2cfd2c, ++ 0x02a80498, ++ 0xfc9608e0, ++ 0xf960feb8, ++ 0x0200fb2c, ++ 0xfd87f991, ++ 0xf7520096, ++ 0xfb3c076a, ++ 0xfd2cfd2c, ++ 0xfbb80014, ++ 0x0096092a, ++ 0x065d02d4, ++ 0xff2cfe00, ++ 0xfe94f90a, ++ 0x079cfc96, ++ 0x027007de, ++ 0x02d402d4, ++ 0x027007de, ++ 0x079cfc96, ++ 0xfe94f90a, ++ 0xff2cfe00, ++ 0x065d02d4, ++ 0x0096092a, ++ 0xfbb80014, ++ 0xfd2cfd2c, ++ 0xfb3c076a, ++ 0xf7520096, ++ 0xfd87f991, ++ 0x0200fb2c, ++ 0xf960feb8, ++ 0xfc9608e0, ++ 0x02a80498, ++ 0xfd2cfd2c, ++ 0x049802a8, ++ 0x08e0fc96, ++ 0xfeb8f960, ++ 0xfb2c0200, ++ 0xf991fd87, ++ 0x0096f752, ++ 0x076afb3c, ++ 0xfd2cfd2c, ++ 0x0014fbb8, ++ 0x092a0096, ++ 0x02d4065d, ++ 0xfe00ff2c, ++ 0xf90afe94, ++ 0xfc96079c, ++ 0x07de0270, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x062a0000, ++ 0xfefa0759, ++ 0x08b80908, ++ 0xf396fc2d, ++ 0xf9d6045c, ++ 0xfc4ef608, ++ 0xf748f596, ++ 0x07b207bf, ++ 0x062a062a, ++ 0xf84ef841, ++ 0xf748f596, ++ 0x03b209f8, ++ 0xf9d6045c, ++ 0x0c6a03d3, ++ 0x08b80908, ++ 0x0106f8a7, ++ 0x062a0000, ++ 0xfefaf8a7, ++ 0x08b8f6f8, ++ 0xf39603d3, ++ 0xf9d6fba4, ++ 0xfc4e09f8, ++ 0xf7480a6a, ++ 0x07b2f841, ++ 0x062af9d6, ++ 0xf84e07bf, ++ 0xf7480a6a, ++ 0x03b2f608, ++ 0xf9d6fba4, ++ 0x0c6afc2d, ++ 0x08b8f6f8, ++ 0x01060759, ++ 0x062a0000, ++ 0xfefa0759, ++ 0x08b80908, ++ 0xf396fc2d, ++ 0xf9d6045c, ++ 0xfc4ef608, ++ 0xf748f596, ++ 0x07b207bf, ++ 0x062a062a, ++ 0xf84ef841, ++ 0xf748f596, ++ 0x03b209f8, ++ 0xf9d6045c, ++ 0x0c6a03d3, ++ 0x08b80908, ++ 0x0106f8a7, ++ 0x062a0000, ++ 0xfefaf8a7, ++ 0x08b8f6f8, ++ 0xf39603d3, ++ 0xf9d6fba4, ++ 0xfc4e09f8, ++ 0xf7480a6a, ++ 0x07b2f841, ++ 0x062af9d6, ++ 0xf84e07bf, ++ 0xf7480a6a, ++ 0x03b2f608, ++ 0xf9d6fba4, ++ 0x0c6afc2d, ++ 0x08b8f6f8, ++ 0x01060759, ++ 0x061c061c, ++ 0xff30009d, ++ 0xffb21141, ++ 0xfd87fb54, ++ 0xf65dfe59, ++ 0x02eef99e, ++ 0x0166f03c, ++ 0xfff809b6, ++ 0x000008a4, ++ 0x000af42b, ++ 0x00eff577, ++ 0xfa840bf2, ++ 0xfc02ff51, ++ 0x08260f67, ++ 0xfff0036f, ++ 0x0842f9c3, ++ 0x00000000, ++ 0x063df7be, ++ 0xfc910010, ++ 0xf099f7da, ++ 0x00af03fe, ++ 0xf40e057c, ++ 0x0a89ff11, ++ 0x0bd5fff6, ++ 0xf75c0000, ++ 0xf64a0008, ++ 0x0fc4fe9a, ++ 0x0662fd12, ++ 0x01a709a3, ++ 0x04ac0279, ++ 0xeebf004e, ++ 0xff6300d0, ++ 0xf9e4f9e4, ++ 0x00d0ff63, ++ 0x004eeebf, ++ 0x027904ac, ++ 0x09a301a7, ++ 0xfd120662, ++ 0xfe9a0fc4, ++ 0x0008f64a, ++ 0x0000f75c, ++ 0xfff60bd5, ++ 0xff110a89, ++ 0x057cf40e, ++ 0x03fe00af, ++ 0xf7daf099, ++ 0x0010fc91, ++ 0xf7be063d, ++ 0x00000000, ++ 0xf9c30842, ++ 0x036ffff0, ++ 0x0f670826, ++ 0xff51fc02, ++ 0x0bf2fa84, ++ 0xf57700ef, ++ 0xf42b000a, ++ 0x08a40000, ++ 0x09b6fff8, ++ 0xf03c0166, ++ 0xf99e02ee, ++ 0xfe59f65d, ++ 0xfb54fd87, ++ 0x1141ffb2, ++ 0x009dff30, ++ 0x05e30000, ++ 0xff060705, ++ 0x085408a0, ++ 0xf425fc59, ++ 0xfa1d042a, ++ 0xfc78f67a, ++ 0xf7acf60e, ++ 0x075a0766, ++ 0x05e305e3, ++ 0xf8a6f89a, ++ 0xf7acf60e, ++ 0x03880986, ++ 0xfa1d042a, ++ 0x0bdb03a7, ++ 0x085408a0, ++ 0x00faf8fb, ++ 0x05e30000, ++ 0xff06f8fb, ++ 0x0854f760, ++ 0xf42503a7, ++ 0xfa1dfbd6, ++ 0xfc780986, ++ 0xf7ac09f2, ++ 0x075af89a, ++ 0x05e3fa1d, ++ 0xf8a60766, ++ 0xf7ac09f2, ++ 0x0388f67a, ++ 0xfa1dfbd6, ++ 0x0bdbfc59, ++ 0x0854f760, ++ 0x00fa0705, ++ 0x05e30000, ++ 0xff060705, ++ 0x085408a0, ++ 0xf425fc59, ++ 0xfa1d042a, ++ 0xfc78f67a, ++ 0xf7acf60e, ++ 0x075a0766, ++ 0x05e305e3, ++ 0xf8a6f89a, ++ 0xf7acf60e, ++ 0x03880986, ++ 0xfa1d042a, ++ 0x0bdb03a7, ++ 0x085408a0, ++ 0x00faf8fb, ++ 0x05e30000, ++ 0xff06f8fb, ++ 0x0854f760, ++ 0xf42503a7, ++ 0xfa1dfbd6, ++ 0xfc780986, ++ 0xf7ac09f2, ++ 0x075af89a, ++ 0x05e3fa1d, ++ 0xf8a60766, ++ 0xf7ac09f2, ++ 0x0388f67a, ++ 0xfa1dfbd6, ++ 0x0bdbfc59, ++ 0x0854f760, ++ 0x00fa0705, ++ 0xfa58fa58, ++ 0xf8f0fe00, ++ 0x0448073d, ++ 0xfdc9fe46, ++ 0xf9910258, ++ 0x089d0407, ++ 0xfd5cf71a, ++ 0x02affde0, ++ 0x083e0496, ++ 0xff5a0740, ++ 0xff7afd97, ++ 0x00fe01f1, ++ 0x0009082e, ++ 0xfa94ff75, ++ 0xfecdf8ea, ++ 0xffb0f693, ++ 0xfd2cfa58, ++ 0x0433ff16, ++ 0xfba405dd, ++ 0xfa610341, ++ 0x06a606cb, ++ 0x0039fd2d, ++ 0x0677fa97, ++ 0x01fa05e0, ++ 0xf896003e, ++ 0x075a068b, ++ 0x012cfc3e, ++ 0xfa23f98d, ++ 0xfc7cfd43, ++ 0xff90fc0d, ++ 0x01c10982, ++ 0x00c601d6, ++ 0xfd2cfd2c, ++ 0x01d600c6, ++ 0x098201c1, ++ 0xfc0dff90, ++ 0xfd43fc7c, ++ 0xf98dfa23, ++ 0xfc3e012c, ++ 0x068b075a, ++ 0x003ef896, ++ 0x05e001fa, ++ 0xfa970677, ++ 0xfd2d0039, ++ 0x06cb06a6, ++ 0x0341fa61, ++ 0x05ddfba4, ++ 0xff160433, ++ 0xfa58fd2c, ++ 0xf693ffb0, ++ 0xf8eafecd, ++ 0xff75fa94, ++ 0x082e0009, ++ 0x01f100fe, ++ 0xfd97ff7a, ++ 0x0740ff5a, ++ 0x0496083e, ++ 0xfde002af, ++ 0xf71afd5c, ++ 0x0407089d, ++ 0x0258f991, ++ 0xfe46fdc9, ++ 0x073d0448, ++ 0xfe00f8f0, ++ 0xfd2cfd2c, ++ 0xfce00500, ++ 0xfc09fddc, ++ 0xfe680157, ++ 0x04c70571, ++ 0xfc3aff21, ++ 0xfcd70228, ++ 0x056d0277, ++ 0x0200fe00, ++ 0x0022f927, ++ 0xfe3c032b, ++ 0xfc44ff3c, ++ 0x03e9fbdb, ++ 0x04570313, ++ 0x04c9ff5c, ++ 0x000d03b8, ++ 0xfa580000, ++ 0xfbe900d2, ++ 0xf9d0fe0b, ++ 0x0125fdf9, ++ 0x042501bf, ++ 0x0328fa2b, ++ 0xffa902f0, ++ 0xfa250157, ++ 0x0200fe00, ++ 0x03740438, ++ 0xff0405fd, ++ 0x030cfe52, ++ 0x0037fb39, ++ 0xff6904c5, ++ 0x04f8fd23, ++ 0xfd31fc1b, ++ 0xfd2cfd2c, ++ 0xfc1bfd31, ++ 0xfd2304f8, ++ 0x04c5ff69, ++ 0xfb390037, ++ 0xfe52030c, ++ 0x05fdff04, ++ 0x04380374, ++ 0xfe000200, ++ 0x0157fa25, ++ 0x02f0ffa9, ++ 0xfa2b0328, ++ 0x01bf0425, ++ 0xfdf90125, ++ 0xfe0bf9d0, ++ 0x00d2fbe9, ++ 0x0000fa58, ++ 0x03b8000d, ++ 0xff5c04c9, ++ 0x03130457, ++ 0xfbdb03e9, ++ 0xff3cfc44, ++ 0x032bfe3c, ++ 0xf9270022, ++ 0xfe000200, ++ 0x0277056d, ++ 0x0228fcd7, ++ 0xff21fc3a, ++ 0x057104c7, ++ 0x0157fe68, ++ 0xfddcfc09, ++ 0x0500fce0, ++ 0xfd2cfd2c, ++ 0x0500fce0, ++ 0xfddcfc09, ++ 0x0157fe68, ++ 0x057104c7, ++ 0xff21fc3a, ++ 0x0228fcd7, ++ 0x0277056d, ++ 0xfe000200, ++ 0xf9270022, ++ 0x032bfe3c, ++ 0xff3cfc44, ++ 0xfbdb03e9, ++ 0x03130457, ++ 0xff5c04c9, ++ 0x03b8000d, ++ 0x0000fa58, ++ 0x00d2fbe9, ++ 0xfe0bf9d0, ++ 0xfdf90125, ++ 0x01bf0425, ++ 0xfa2b0328, ++ 0x02f0ffa9, ++ 0x0157fa25, ++ 0xfe000200, ++ 0x04380374, ++ 0x05fdff04, ++ 0xfe52030c, ++ 0xfb390037, ++ 0x04c5ff69, ++ 0xfd2304f8, ++ 0xfc1bfd31, ++ 0xfd2cfd2c, ++ 0xfd31fc1b, ++ 0x04f8fd23, ++ 0xff6904c5, ++ 0x0037fb39, ++ 0x030cfe52, ++ 0xff0405fd, ++ 0x03740438, ++ 0x0200fe00, ++ 0xfa250157, ++ 0xffa902f0, ++ 0x0328fa2b, ++ 0x042501bf, ++ 0x0125fdf9, ++ 0xf9d0fe0b, ++ 0xfbe900d2, ++ 0xfa580000, ++ 0x000d03b8, ++ 0x04c9ff5c, ++ 0x04570313, ++ 0x03e9fbdb, ++ 0xfc44ff3c, ++ 0xfe3c032b, ++ 0x0022f927, ++ 0x0200fe00, ++ 0x056d0277, ++ 0xfcd70228, ++ 0xfc3aff21, ++ 0x04c70571, ++ 0xfe680157, ++ 0xfc09fddc, ++ 0xfce00500, ++ 0x05a80000, ++ 0xff1006be, ++ 0x0800084a, ++ 0xf49cfc7e, ++ 0xfa580400, ++ 0xfc9cf6da, ++ 0xf800f672, ++ 0x0710071c, ++ 0x05a805a8, ++ 0xf8f0f8e4, ++ 0xf800f672, ++ 0x03640926, ++ 0xfa580400, ++ 0x0b640382, ++ 0x0800084a, ++ 0x00f0f942, ++ 0x05a80000, ++ 0xff10f942, ++ 0x0800f7b6, ++ 0xf49c0382, ++ 0xfa58fc00, ++ 0xfc9c0926, ++ 0xf800098e, ++ 0x0710f8e4, ++ 0x05a8fa58, ++ 0xf8f0071c, ++ 0xf800098e, ++ 0x0364f6da, ++ 0xfa58fc00, ++ 0x0b64fc7e, ++ 0x0800f7b6, ++ 0x00f006be, ++ 0x05a80000, ++ 0xff1006be, ++ 0x0800084a, ++ 0xf49cfc7e, ++ 0xfa580400, ++ 0xfc9cf6da, ++ 0xf800f672, ++ 0x0710071c, ++ 0x05a805a8, ++ 0xf8f0f8e4, ++ 0xf800f672, ++ 0x03640926, ++ 0xfa580400, ++ 0x0b640382, ++ 0x0800084a, ++ 0x00f0f942, ++ 0x05a80000, ++ 0xff10f942, ++ 0x0800f7b6, ++ 0xf49c0382, ++ 0xfa58fc00, ++ 0xfc9c0926, ++ 0xf800098e, ++ 0x0710f8e4, ++ 0x05a8fa58, ++ 0xf8f0071c, ++ 0xf800098e, ++ 0x0364f6da, ++ 0xfa58fc00, ++ 0x0b64fc7e, ++ 0x0800f7b6, ++ 0x00f006be, ++}; ++ ++const u32 noise_var_tbl_rev3[] = { ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++ 0x02110211, ++ 0x0000014d, ++}; ++ ++static const u16 mcs_tbl_rev3[] = { ++ 0x0000, ++ 0x0008, ++ 0x000a, ++ 0x0010, ++ 0x0012, ++ 0x0019, ++ 0x001a, ++ 0x001c, ++ 0x0080, ++ 0x0088, ++ 0x008a, ++ 0x0090, ++ 0x0092, ++ 0x0099, ++ 0x009a, ++ 0x009c, ++ 0x0100, ++ 0x0108, ++ 0x010a, ++ 0x0110, ++ 0x0112, ++ 0x0119, ++ 0x011a, ++ 0x011c, ++ 0x0180, ++ 0x0188, ++ 0x018a, ++ 0x0190, ++ 0x0192, ++ 0x0199, ++ 0x019a, ++ 0x019c, ++ 0x0000, ++ 0x0098, ++ 0x00a0, ++ 0x00a8, ++ 0x009a, ++ 0x00a2, ++ 0x00aa, ++ 0x0120, ++ 0x0128, ++ 0x0128, ++ 0x0130, ++ 0x0138, ++ 0x0138, ++ 0x0140, ++ 0x0122, ++ 0x012a, ++ 0x012a, ++ 0x0132, ++ 0x013a, ++ 0x013a, ++ 0x0142, ++ 0x01a8, ++ 0x01b0, ++ 0x01b8, ++ 0x01b0, ++ 0x01b8, ++ 0x01c0, ++ 0x01c8, ++ 0x01c0, ++ 0x01c8, ++ 0x01d0, ++ 0x01d0, ++ 0x01d8, ++ 0x01aa, ++ 0x01b2, ++ 0x01ba, ++ 0x01b2, ++ 0x01ba, ++ 0x01c2, ++ 0x01ca, ++ 0x01c2, ++ 0x01ca, ++ 0x01d2, ++ 0x01d2, ++ 0x01da, ++ 0x0001, ++ 0x0002, ++ 0x0004, ++ 0x0009, ++ 0x000c, ++ 0x0011, ++ 0x0014, ++ 0x0018, ++ 0x0020, ++ 0x0021, ++ 0x0022, ++ 0x0024, ++ 0x0081, ++ 0x0082, ++ 0x0084, ++ 0x0089, ++ 0x008c, ++ 0x0091, ++ 0x0094, ++ 0x0098, ++ 0x00a0, ++ 0x00a1, ++ 0x00a2, ++ 0x00a4, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++ 0x0007, ++}; ++ ++static const u32 tdi_tbl20_ant0_rev3[] = { ++ 0x00091226, ++ 0x000a1429, ++ 0x000b56ad, ++ 0x000c58b0, ++ 0x000d5ab3, ++ 0x000e9cb6, ++ 0x000f9eba, ++ 0x0000c13d, ++ 0x00020301, ++ 0x00030504, ++ 0x00040708, ++ 0x0005090b, ++ 0x00064b8e, ++ 0x00095291, ++ 0x000a5494, ++ 0x000b9718, ++ 0x000c9927, ++ 0x000d9b2a, ++ 0x000edd2e, ++ 0x000fdf31, ++ 0x000101b4, ++ 0x000243b7, ++ 0x000345bb, ++ 0x000447be, ++ 0x00058982, ++ 0x00068c05, ++ 0x00099309, ++ 0x000a950c, ++ 0x000bd78f, ++ 0x000cd992, ++ 0x000ddb96, ++ 0x000f1d99, ++ 0x00005fa8, ++ 0x0001422c, ++ 0x0002842f, ++ 0x00038632, ++ 0x00048835, ++ 0x0005ca38, ++ 0x0006ccbc, ++ 0x0009d3bf, ++ 0x000b1603, ++ 0x000c1806, ++ 0x000d1a0a, ++ 0x000e1c0d, ++ 0x000f5e10, ++ 0x00008093, ++ 0x00018297, ++ 0x0002c49a, ++ 0x0003c680, ++ 0x0004c880, ++ 0x00060b00, ++ 0x00070d00, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl20_ant1_rev3[] = { ++ 0x00014b26, ++ 0x00028d29, ++ 0x000393ad, ++ 0x00049630, ++ 0x0005d833, ++ 0x0006da36, ++ 0x00099c3a, ++ 0x000a9e3d, ++ 0x000bc081, ++ 0x000cc284, ++ 0x000dc488, ++ 0x000f068b, ++ 0x0000488e, ++ 0x00018b91, ++ 0x0002d214, ++ 0x0003d418, ++ 0x0004d6a7, ++ 0x000618aa, ++ 0x00071aae, ++ 0x0009dcb1, ++ 0x000b1eb4, ++ 0x000c0137, ++ 0x000d033b, ++ 0x000e053e, ++ 0x000f4702, ++ 0x00008905, ++ 0x00020c09, ++ 0x0003128c, ++ 0x0004148f, ++ 0x00051712, ++ 0x00065916, ++ 0x00091b19, ++ 0x000a1d28, ++ 0x000b5f2c, ++ 0x000c41af, ++ 0x000d43b2, ++ 0x000e85b5, ++ 0x000f87b8, ++ 0x0000c9bc, ++ 0x00024cbf, ++ 0x00035303, ++ 0x00045506, ++ 0x0005978a, ++ 0x0006998d, ++ 0x00095b90, ++ 0x000a5d93, ++ 0x000b9f97, ++ 0x000c821a, ++ 0x000d8400, ++ 0x000ec600, ++ 0x000fc800, ++ 0x00010a00, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl40_ant0_rev3[] = { ++ 0x0011a346, ++ 0x00136ccf, ++ 0x0014f5d9, ++ 0x001641e2, ++ 0x0017cb6b, ++ 0x00195475, ++ 0x001b2383, ++ 0x001cad0c, ++ 0x001e7616, ++ 0x0000821f, ++ 0x00020ba8, ++ 0x0003d4b2, ++ 0x00056447, ++ 0x00072dd0, ++ 0x0008b6da, ++ 0x000a02e3, ++ 0x000b8c6c, ++ 0x000d15f6, ++ 0x0011e484, ++ 0x0013ae0d, ++ 0x00153717, ++ 0x00168320, ++ 0x00180ca9, ++ 0x00199633, ++ 0x001b6548, ++ 0x001ceed1, ++ 0x001eb7db, ++ 0x0000c3e4, ++ 0x00024d6d, ++ 0x000416f7, ++ 0x0005a585, ++ 0x00076f0f, ++ 0x0008f818, ++ 0x000a4421, ++ 0x000bcdab, ++ 0x000d9734, ++ 0x00122649, ++ 0x0013efd2, ++ 0x001578dc, ++ 0x0016c4e5, ++ 0x00184e6e, ++ 0x001a17f8, ++ 0x001ba686, ++ 0x001d3010, ++ 0x001ef999, ++ 0x00010522, ++ 0x00028eac, ++ 0x00045835, ++ 0x0005e74a, ++ 0x0007b0d3, ++ 0x00093a5d, ++ 0x000a85e6, ++ 0x000c0f6f, ++ 0x000dd8f9, ++ 0x00126787, ++ 0x00143111, ++ 0x0015ba9a, ++ 0x00170623, ++ 0x00188fad, ++ 0x001a5936, ++ 0x001be84b, ++ 0x001db1d4, ++ 0x001f3b5e, ++ 0x000146e7, ++ 0x00031070, ++ 0x000499fa, ++ 0x00062888, ++ 0x0007f212, ++ 0x00097b9b, ++ 0x000ac7a4, ++ 0x000c50ae, ++ 0x000e1a37, ++ 0x0012a94c, ++ 0x001472d5, ++ 0x0015fc5f, ++ 0x00174868, ++ 0x0018d171, ++ 0x001a9afb, ++ 0x001c2989, ++ 0x001df313, ++ 0x001f7c9c, ++ 0x000188a5, ++ 0x000351af, ++ 0x0004db38, ++ 0x0006aa4d, ++ 0x000833d7, ++ 0x0009bd60, ++ 0x000b0969, ++ 0x000c9273, ++ 0x000e5bfc, ++ 0x00132a8a, ++ 0x0014b414, ++ 0x00163d9d, ++ 0x001789a6, ++ 0x001912b0, ++ 0x001adc39, ++ 0x001c6bce, ++ 0x001e34d8, ++ 0x001fbe61, ++ 0x0001ca6a, ++ 0x00039374, ++ 0x00051cfd, ++ 0x0006ec0b, ++ 0x00087515, ++ 0x0009fe9e, ++ 0x000b4aa7, ++ 0x000cd3b1, ++ 0x000e9d3a, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 tdi_tbl40_ant1_rev3[] = { ++ 0x001edb36, ++ 0x000129ca, ++ 0x0002b353, ++ 0x00047cdd, ++ 0x0005c8e6, ++ 0x000791ef, ++ 0x00091bf9, ++ 0x000aaa07, ++ 0x000c3391, ++ 0x000dfd1a, ++ 0x00120923, ++ 0x0013d22d, ++ 0x00155c37, ++ 0x0016eacb, ++ 0x00187454, ++ 0x001a3dde, ++ 0x001b89e7, ++ 0x001d12f0, ++ 0x001f1cfa, ++ 0x00016b88, ++ 0x00033492, ++ 0x0004be1b, ++ 0x00060a24, ++ 0x0007d32e, ++ 0x00095d38, ++ 0x000aec4c, ++ 0x000c7555, ++ 0x000e3edf, ++ 0x00124ae8, ++ 0x001413f1, ++ 0x0015a37b, ++ 0x00172c89, ++ 0x0018b593, ++ 0x001a419c, ++ 0x001bcb25, ++ 0x001d942f, ++ 0x001f63b9, ++ 0x0001ad4d, ++ 0x00037657, ++ 0x0004c260, ++ 0x00068be9, ++ 0x000814f3, ++ 0x0009a47c, ++ 0x000b2d8a, ++ 0x000cb694, ++ 0x000e429d, ++ 0x00128c26, ++ 0x001455b0, ++ 0x0015e4ba, ++ 0x00176e4e, ++ 0x0018f758, ++ 0x001a8361, ++ 0x001c0cea, ++ 0x001dd674, ++ 0x001fa57d, ++ 0x0001ee8b, ++ 0x0003b795, ++ 0x0005039e, ++ 0x0006cd27, ++ 0x000856b1, ++ 0x0009e5c6, ++ 0x000b6f4f, ++ 0x000cf859, ++ 0x000e8462, ++ 0x00130deb, ++ 0x00149775, ++ 0x00162603, ++ 0x0017af8c, ++ 0x00193896, ++ 0x001ac49f, ++ 0x001c4e28, ++ 0x001e17b2, ++ 0x0000a6c7, ++ 0x00023050, ++ 0x0003f9da, ++ 0x00054563, ++ 0x00070eec, ++ 0x00089876, ++ 0x000a2704, ++ 0x000bb08d, ++ 0x000d3a17, ++ 0x001185a0, ++ 0x00134f29, ++ 0x0014d8b3, ++ 0x001667c8, ++ 0x0017f151, ++ 0x00197adb, ++ 0x001b0664, ++ 0x001c8fed, ++ 0x001e5977, ++ 0x0000e805, ++ 0x0002718f, ++ 0x00043b18, ++ 0x000586a1, ++ 0x0007502b, ++ 0x0008d9b4, ++ 0x000a68c9, ++ 0x000bf252, ++ 0x000dbbdc, ++ 0x0011c7e5, ++ 0x001390ee, ++ 0x00151a78, ++ 0x0016a906, ++ 0x00183290, ++ 0x0019bc19, ++ 0x001b4822, ++ 0x001cd12c, ++ 0x001e9ab5, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 pltlut_tbl_rev3[] = { ++ 0x76540213, ++ 0x62407351, ++ 0x76543210, ++ 0x76540213, ++ 0x76540213, ++ 0x76430521, ++}; ++ ++static const u32 chanest_tbl_rev3[] = { ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x44444444, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++ 0x10101010, ++}; ++ ++static const u8 frame_lut_rev3[] = { ++ 0x02, ++ 0x04, ++ 0x14, ++ 0x14, ++ 0x03, ++ 0x05, ++ 0x16, ++ 0x16, ++ 0x0a, ++ 0x0c, ++ 0x1c, ++ 0x1c, ++ 0x0b, ++ 0x0d, ++ 0x1e, ++ 0x1e, ++ 0x06, ++ 0x08, ++ 0x18, ++ 0x18, ++ 0x07, ++ 0x09, ++ 0x1a, ++ 0x1a, ++ 0x0e, ++ 0x10, ++ 0x20, ++ 0x28, ++ 0x0f, ++ 0x11, ++ 0x22, ++ 0x2a, ++}; ++ ++static const u8 est_pwr_lut_core0_rev3[] = { ++ 0x55, ++ 0x54, ++ 0x54, ++ 0x53, ++ 0x52, ++ 0x52, ++ 0x51, ++ 0x51, ++ 0x50, ++ 0x4f, ++ 0x4f, ++ 0x4e, ++ 0x4e, ++ 0x4d, ++ 0x4c, ++ 0x4c, ++ 0x4b, ++ 0x4a, ++ 0x49, ++ 0x49, ++ 0x48, ++ 0x47, ++ 0x46, ++ 0x46, ++ 0x45, ++ 0x44, ++ 0x43, ++ 0x42, ++ 0x41, ++ 0x40, ++ 0x40, ++ 0x3f, ++ 0x3e, ++ 0x3d, ++ 0x3c, ++ 0x3a, ++ 0x39, ++ 0x38, ++ 0x37, ++ 0x36, ++ 0x35, ++ 0x33, ++ 0x32, ++ 0x31, ++ 0x2f, ++ 0x2e, ++ 0x2c, ++ 0x2b, ++ 0x29, ++ 0x27, ++ 0x25, ++ 0x23, ++ 0x21, ++ 0x1f, ++ 0x1d, ++ 0x1a, ++ 0x18, ++ 0x15, ++ 0x12, ++ 0x0e, ++ 0x0b, ++ 0x07, ++ 0x02, ++ 0xfd, ++}; ++ ++static const u8 est_pwr_lut_core1_rev3[] = { ++ 0x55, ++ 0x54, ++ 0x54, ++ 0x53, ++ 0x52, ++ 0x52, ++ 0x51, ++ 0x51, ++ 0x50, ++ 0x4f, ++ 0x4f, ++ 0x4e, ++ 0x4e, ++ 0x4d, ++ 0x4c, ++ 0x4c, ++ 0x4b, ++ 0x4a, ++ 0x49, ++ 0x49, ++ 0x48, ++ 0x47, ++ 0x46, ++ 0x46, ++ 0x45, ++ 0x44, ++ 0x43, ++ 0x42, ++ 0x41, ++ 0x40, ++ 0x40, ++ 0x3f, ++ 0x3e, ++ 0x3d, ++ 0x3c, ++ 0x3a, ++ 0x39, ++ 0x38, ++ 0x37, ++ 0x36, ++ 0x35, ++ 0x33, ++ 0x32, ++ 0x31, ++ 0x2f, ++ 0x2e, ++ 0x2c, ++ 0x2b, ++ 0x29, ++ 0x27, ++ 0x25, ++ 0x23, ++ 0x21, ++ 0x1f, ++ 0x1d, ++ 0x1a, ++ 0x18, ++ 0x15, ++ 0x12, ++ 0x0e, ++ 0x0b, ++ 0x07, ++ 0x02, ++ 0xfd, ++}; ++ ++static const u8 adj_pwr_lut_core0_rev3[] = { ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++}; ++ ++static const u8 adj_pwr_lut_core1_rev3[] = { ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x00, ++}; ++ ++static const u32 gainctrl_lut_core0_rev3[] = { ++ 0x5bf70044, ++ 0x5bf70042, ++ 0x5bf70040, ++ 0x5bf7003e, ++ 0x5bf7003c, ++ 0x5bf7003b, ++ 0x5bf70039, ++ 0x5bf70037, ++ 0x5bf70036, ++ 0x5bf70034, ++ 0x5bf70033, ++ 0x5bf70031, ++ 0x5bf70030, ++ 0x5ba70044, ++ 0x5ba70042, ++ 0x5ba70040, ++ 0x5ba7003e, ++ 0x5ba7003c, ++ 0x5ba7003b, ++ 0x5ba70039, ++ 0x5ba70037, ++ 0x5ba70036, ++ 0x5ba70034, ++ 0x5ba70033, ++ 0x5b770044, ++ 0x5b770042, ++ 0x5b770040, ++ 0x5b77003e, ++ 0x5b77003c, ++ 0x5b77003b, ++ 0x5b770039, ++ 0x5b770037, ++ 0x5b770036, ++ 0x5b770034, ++ 0x5b770033, ++ 0x5b770031, ++ 0x5b770030, ++ 0x5b77002f, ++ 0x5b77002d, ++ 0x5b77002c, ++ 0x5b470044, ++ 0x5b470042, ++ 0x5b470040, ++ 0x5b47003e, ++ 0x5b47003c, ++ 0x5b47003b, ++ 0x5b470039, ++ 0x5b470037, ++ 0x5b470036, ++ 0x5b470034, ++ 0x5b470033, ++ 0x5b470031, ++ 0x5b470030, ++ 0x5b47002f, ++ 0x5b47002d, ++ 0x5b47002c, ++ 0x5b47002b, ++ 0x5b47002a, ++ 0x5b270044, ++ 0x5b270042, ++ 0x5b270040, ++ 0x5b27003e, ++ 0x5b27003c, ++ 0x5b27003b, ++ 0x5b270039, ++ 0x5b270037, ++ 0x5b270036, ++ 0x5b270034, ++ 0x5b270033, ++ 0x5b270031, ++ 0x5b270030, ++ 0x5b27002f, ++ 0x5b170044, ++ 0x5b170042, ++ 0x5b170040, ++ 0x5b17003e, ++ 0x5b17003c, ++ 0x5b17003b, ++ 0x5b170039, ++ 0x5b170037, ++ 0x5b170036, ++ 0x5b170034, ++ 0x5b170033, ++ 0x5b170031, ++ 0x5b170030, ++ 0x5b17002f, ++ 0x5b17002d, ++ 0x5b17002c, ++ 0x5b17002b, ++ 0x5b17002a, ++ 0x5b170028, ++ 0x5b170027, ++ 0x5b170026, ++ 0x5b170025, ++ 0x5b170024, ++ 0x5b170023, ++ 0x5b070044, ++ 0x5b070042, ++ 0x5b070040, ++ 0x5b07003e, ++ 0x5b07003c, ++ 0x5b07003b, ++ 0x5b070039, ++ 0x5b070037, ++ 0x5b070036, ++ 0x5b070034, ++ 0x5b070033, ++ 0x5b070031, ++ 0x5b070030, ++ 0x5b07002f, ++ 0x5b07002d, ++ 0x5b07002c, ++ 0x5b07002b, ++ 0x5b07002a, ++ 0x5b070028, ++ 0x5b070027, ++ 0x5b070026, ++ 0x5b070025, ++ 0x5b070024, ++ 0x5b070023, ++ 0x5b070022, ++ 0x5b070021, ++ 0x5b070020, ++ 0x5b07001f, ++ 0x5b07001e, ++ 0x5b07001d, ++ 0x5b07001d, ++ 0x5b07001c, ++}; ++ ++static const u32 gainctrl_lut_core1_rev3[] = { ++ 0x5bf70044, ++ 0x5bf70042, ++ 0x5bf70040, ++ 0x5bf7003e, ++ 0x5bf7003c, ++ 0x5bf7003b, ++ 0x5bf70039, ++ 0x5bf70037, ++ 0x5bf70036, ++ 0x5bf70034, ++ 0x5bf70033, ++ 0x5bf70031, ++ 0x5bf70030, ++ 0x5ba70044, ++ 0x5ba70042, ++ 0x5ba70040, ++ 0x5ba7003e, ++ 0x5ba7003c, ++ 0x5ba7003b, ++ 0x5ba70039, ++ 0x5ba70037, ++ 0x5ba70036, ++ 0x5ba70034, ++ 0x5ba70033, ++ 0x5b770044, ++ 0x5b770042, ++ 0x5b770040, ++ 0x5b77003e, ++ 0x5b77003c, ++ 0x5b77003b, ++ 0x5b770039, ++ 0x5b770037, ++ 0x5b770036, ++ 0x5b770034, ++ 0x5b770033, ++ 0x5b770031, ++ 0x5b770030, ++ 0x5b77002f, ++ 0x5b77002d, ++ 0x5b77002c, ++ 0x5b470044, ++ 0x5b470042, ++ 0x5b470040, ++ 0x5b47003e, ++ 0x5b47003c, ++ 0x5b47003b, ++ 0x5b470039, ++ 0x5b470037, ++ 0x5b470036, ++ 0x5b470034, ++ 0x5b470033, ++ 0x5b470031, ++ 0x5b470030, ++ 0x5b47002f, ++ 0x5b47002d, ++ 0x5b47002c, ++ 0x5b47002b, ++ 0x5b47002a, ++ 0x5b270044, ++ 0x5b270042, ++ 0x5b270040, ++ 0x5b27003e, ++ 0x5b27003c, ++ 0x5b27003b, ++ 0x5b270039, ++ 0x5b270037, ++ 0x5b270036, ++ 0x5b270034, ++ 0x5b270033, ++ 0x5b270031, ++ 0x5b270030, ++ 0x5b27002f, ++ 0x5b170044, ++ 0x5b170042, ++ 0x5b170040, ++ 0x5b17003e, ++ 0x5b17003c, ++ 0x5b17003b, ++ 0x5b170039, ++ 0x5b170037, ++ 0x5b170036, ++ 0x5b170034, ++ 0x5b170033, ++ 0x5b170031, ++ 0x5b170030, ++ 0x5b17002f, ++ 0x5b17002d, ++ 0x5b17002c, ++ 0x5b17002b, ++ 0x5b17002a, ++ 0x5b170028, ++ 0x5b170027, ++ 0x5b170026, ++ 0x5b170025, ++ 0x5b170024, ++ 0x5b170023, ++ 0x5b070044, ++ 0x5b070042, ++ 0x5b070040, ++ 0x5b07003e, ++ 0x5b07003c, ++ 0x5b07003b, ++ 0x5b070039, ++ 0x5b070037, ++ 0x5b070036, ++ 0x5b070034, ++ 0x5b070033, ++ 0x5b070031, ++ 0x5b070030, ++ 0x5b07002f, ++ 0x5b07002d, ++ 0x5b07002c, ++ 0x5b07002b, ++ 0x5b07002a, ++ 0x5b070028, ++ 0x5b070027, ++ 0x5b070026, ++ 0x5b070025, ++ 0x5b070024, ++ 0x5b070023, ++ 0x5b070022, ++ 0x5b070021, ++ 0x5b070020, ++ 0x5b07001f, ++ 0x5b07001e, ++ 0x5b07001d, ++ 0x5b07001d, ++ 0x5b07001c, ++}; ++ ++static const u32 iq_lut_core0_rev3[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u32 iq_lut_core1_rev3[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++static const u16 loft_lut_core0_rev3[] = { ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u16 loft_lut_core1_rev3[] = { ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++ 0x0000, ++}; ++ ++static const u16 papd_comp_rfpwr_tbl_core0_rev3[] = { ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++}; ++ ++static const u16 papd_comp_rfpwr_tbl_core1_rev3[] = { ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x0036, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x002a, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x001e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x000e, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01fc, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01ee, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++ 0x01d6, ++}; ++ ++static const u32 papd_comp_epsilon_tbl_core0_rev3[] = { ++ 0x00000000, ++ 0x00001fa0, ++ 0x00019f78, ++ 0x0001df7e, ++ 0x03fa9f86, ++ 0x03fd1f90, ++ 0x03fe5f8a, ++ 0x03fb1f94, ++ 0x03fd9fa0, ++ 0x00009f98, ++ 0x03fd1fac, ++ 0x03ff9fa2, ++ 0x03fe9fae, ++ 0x00001fae, ++ 0x03fddfb4, ++ 0x03ff1fb8, ++ 0x03ff9fbc, ++ 0x03ffdfbe, ++ 0x03fe9fc2, ++ 0x03fedfc6, ++ 0x03fedfc6, ++ 0x03ff9fc8, ++ 0x03ff5fc6, ++ 0x03fedfc2, ++ 0x03ff9fc0, ++ 0x03ff5fac, ++ 0x03ff5fac, ++ 0x03ff9fa2, ++ 0x03ff9fa6, ++ 0x03ff9faa, ++ 0x03ff5fb0, ++ 0x03ff5fb4, ++ 0x03ff1fca, ++ 0x03ff5fce, ++ 0x03fcdfdc, ++ 0x03fb4006, ++ 0x00000030, ++ 0x03ff808a, ++ 0x03ff80da, ++ 0x0000016c, ++ 0x03ff8318, ++ 0x03ff063a, ++ 0x03fd8bd6, ++ 0x00014ffe, ++ 0x00034ffe, ++ 0x00034ffe, ++ 0x0003cffe, ++ 0x00040ffe, ++ 0x00040ffe, ++ 0x0003cffe, ++ 0x0003cffe, ++ 0x00020ffe, ++ 0x03fe0ffe, ++ 0x03fdcffe, ++ 0x03f94ffe, ++ 0x03f54ffe, ++ 0x03f44ffe, ++ 0x03ef8ffe, ++ 0x03ee0ffe, ++ 0x03ebcffe, ++ 0x03e8cffe, ++ 0x03e74ffe, ++ 0x03e4cffe, ++ 0x03e38ffe, ++}; ++ ++static const u32 papd_cal_scalars_tbl_core0_rev3[] = { ++ 0x05af005a, ++ 0x0571005e, ++ 0x05040066, ++ 0x04bd006c, ++ 0x047d0072, ++ 0x04430078, ++ 0x03f70081, ++ 0x03cb0087, ++ 0x03870091, ++ 0x035e0098, ++ 0x032e00a1, ++ 0x030300aa, ++ 0x02d800b4, ++ 0x02ae00bf, ++ 0x028900ca, ++ 0x026400d6, ++ 0x024100e3, ++ 0x022200f0, ++ 0x020200ff, ++ 0x01e5010e, ++ 0x01ca011e, ++ 0x01b0012f, ++ 0x01990140, ++ 0x01830153, ++ 0x016c0168, ++ 0x0158017d, ++ 0x01450193, ++ 0x013301ab, ++ 0x012101c5, ++ 0x011101e0, ++ 0x010201fc, ++ 0x00f4021a, ++ 0x00e6011d, ++ 0x00d9012e, ++ 0x00cd0140, ++ 0x00c20153, ++ 0x00b70167, ++ 0x00ac017c, ++ 0x00a30193, ++ 0x009a01ab, ++ 0x009101c4, ++ 0x008901df, ++ 0x008101fb, ++ 0x007a0219, ++ 0x00730239, ++ 0x006d025b, ++ 0x0067027e, ++ 0x006102a4, ++ 0x005c02cc, ++ 0x005602f6, ++ 0x00520323, ++ 0x004d0353, ++ 0x00490385, ++ 0x004503bb, ++ 0x004103f3, ++ 0x003d042f, ++ 0x003a046f, ++ 0x003704b2, ++ 0x003404f9, ++ 0x00310545, ++ 0x002e0596, ++ 0x002b05f5, ++ 0x00290640, ++ 0x002606a4, ++}; ++ ++static const u32 papd_comp_epsilon_tbl_core1_rev3[] = { ++ 0x00000000, ++ 0x00001fa0, ++ 0x00019f78, ++ 0x0001df7e, ++ 0x03fa9f86, ++ 0x03fd1f90, ++ 0x03fe5f8a, ++ 0x03fb1f94, ++ 0x03fd9fa0, ++ 0x00009f98, ++ 0x03fd1fac, ++ 0x03ff9fa2, ++ 0x03fe9fae, ++ 0x00001fae, ++ 0x03fddfb4, ++ 0x03ff1fb8, ++ 0x03ff9fbc, ++ 0x03ffdfbe, ++ 0x03fe9fc2, ++ 0x03fedfc6, ++ 0x03fedfc6, ++ 0x03ff9fc8, ++ 0x03ff5fc6, ++ 0x03fedfc2, ++ 0x03ff9fc0, ++ 0x03ff5fac, ++ 0x03ff5fac, ++ 0x03ff9fa2, ++ 0x03ff9fa6, ++ 0x03ff9faa, ++ 0x03ff5fb0, ++ 0x03ff5fb4, ++ 0x03ff1fca, ++ 0x03ff5fce, ++ 0x03fcdfdc, ++ 0x03fb4006, ++ 0x00000030, ++ 0x03ff808a, ++ 0x03ff80da, ++ 0x0000016c, ++ 0x03ff8318, ++ 0x03ff063a, ++ 0x03fd8bd6, ++ 0x00014ffe, ++ 0x00034ffe, ++ 0x00034ffe, ++ 0x0003cffe, ++ 0x00040ffe, ++ 0x00040ffe, ++ 0x0003cffe, ++ 0x0003cffe, ++ 0x00020ffe, ++ 0x03fe0ffe, ++ 0x03fdcffe, ++ 0x03f94ffe, ++ 0x03f54ffe, ++ 0x03f44ffe, ++ 0x03ef8ffe, ++ 0x03ee0ffe, ++ 0x03ebcffe, ++ 0x03e8cffe, ++ 0x03e74ffe, ++ 0x03e4cffe, ++ 0x03e38ffe, ++}; ++ ++static const u32 papd_cal_scalars_tbl_core1_rev3[] = { ++ 0x05af005a, ++ 0x0571005e, ++ 0x05040066, ++ 0x04bd006c, ++ 0x047d0072, ++ 0x04430078, ++ 0x03f70081, ++ 0x03cb0087, ++ 0x03870091, ++ 0x035e0098, ++ 0x032e00a1, ++ 0x030300aa, ++ 0x02d800b4, ++ 0x02ae00bf, ++ 0x028900ca, ++ 0x026400d6, ++ 0x024100e3, ++ 0x022200f0, ++ 0x020200ff, ++ 0x01e5010e, ++ 0x01ca011e, ++ 0x01b0012f, ++ 0x01990140, ++ 0x01830153, ++ 0x016c0168, ++ 0x0158017d, ++ 0x01450193, ++ 0x013301ab, ++ 0x012101c5, ++ 0x011101e0, ++ 0x010201fc, ++ 0x00f4021a, ++ 0x00e6011d, ++ 0x00d9012e, ++ 0x00cd0140, ++ 0x00c20153, ++ 0x00b70167, ++ 0x00ac017c, ++ 0x00a30193, ++ 0x009a01ab, ++ 0x009101c4, ++ 0x008901df, ++ 0x008101fb, ++ 0x007a0219, ++ 0x00730239, ++ 0x006d025b, ++ 0x0067027e, ++ 0x006102a4, ++ 0x005c02cc, ++ 0x005602f6, ++ 0x00520323, ++ 0x004d0353, ++ 0x00490385, ++ 0x004503bb, ++ 0x004103f3, ++ 0x003d042f, ++ 0x003a046f, ++ 0x003704b2, ++ 0x003404f9, ++ 0x00310545, ++ 0x002e0596, ++ 0x002b05f5, ++ 0x00290640, ++ 0x002606a4, ++}; ++ ++const struct phytbl_info mimophytbl_info_rev3_volatile[] = { ++ {&ant_swctrl_tbl_rev3, ++ sizeof(ant_swctrl_tbl_rev3) / sizeof(ant_swctrl_tbl_rev3[0]), 9, 0, 16} ++ , ++}; ++ ++const struct phytbl_info mimophytbl_info_rev3_volatile1[] = { ++ {&ant_swctrl_tbl_rev3_1, ++ sizeof(ant_swctrl_tbl_rev3_1) / sizeof(ant_swctrl_tbl_rev3_1[0]), 9, 0, ++ 16} ++ , ++}; ++ ++const struct phytbl_info mimophytbl_info_rev3_volatile2[] = { ++ {&ant_swctrl_tbl_rev3_2, ++ sizeof(ant_swctrl_tbl_rev3_2) / sizeof(ant_swctrl_tbl_rev3_2[0]), 9, 0, ++ 16} ++ , ++}; ++ ++const struct phytbl_info mimophytbl_info_rev3_volatile3[] = { ++ {&ant_swctrl_tbl_rev3_3, ++ sizeof(ant_swctrl_tbl_rev3_3) / sizeof(ant_swctrl_tbl_rev3_3[0]), 9, 0, ++ 16} ++ , ++}; ++ ++const struct phytbl_info mimophytbl_info_rev3[] = { ++ {&frame_struct_rev3, ++ sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32} ++ , ++ {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]), ++ 11, 0, 16} ++ , ++ {&tmap_tbl_rev3, sizeof(tmap_tbl_rev3) / sizeof(tmap_tbl_rev3[0]), 12, ++ 0, 32} ++ , ++ {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]), ++ 13, 0, 32} ++ , ++ {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]), ++ 14, 0, 32} ++ , ++ {&noise_var_tbl_rev3, ++ sizeof(noise_var_tbl_rev3) / sizeof(noise_var_tbl_rev3[0]), 16, 0, 32} ++ , ++ {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0, ++ 16} ++ , ++ {&tdi_tbl20_ant0_rev3, ++ sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128, ++ 32} ++ , ++ {&tdi_tbl20_ant1_rev3, ++ sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256, ++ 32} ++ , ++ {&tdi_tbl40_ant0_rev3, ++ sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640, ++ 32} ++ , ++ {&tdi_tbl40_ant1_rev3, ++ sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768, ++ 32} ++ , ++ {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]), ++ 20, 0, 32} ++ , ++ {&chanest_tbl_rev3, ++ sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32} ++ , ++ {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]), ++ 24, 0, 8} ++ , ++ {&est_pwr_lut_core0_rev3, ++ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, ++ 0, 8} ++ , ++ {&est_pwr_lut_core1_rev3, ++ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, ++ 0, 8} ++ , ++ {&adj_pwr_lut_core0_rev3, ++ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, ++ 64, 8} ++ , ++ {&adj_pwr_lut_core1_rev3, ++ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, ++ 64, 8} ++ , ++ {&gainctrl_lut_core0_rev3, ++ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), ++ 26, 192, 32} ++ , ++ {&gainctrl_lut_core1_rev3, ++ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), ++ 27, 192, 32} ++ , ++ {&iq_lut_core0_rev3, ++ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} ++ , ++ {&iq_lut_core1_rev3, ++ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} ++ , ++ {&loft_lut_core0_rev3, ++ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, ++ 16} ++ , ++ {&loft_lut_core1_rev3, ++ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, ++ 16} ++}; ++ ++const u32 mimophytbl_info_sz_rev3 = ++ sizeof(mimophytbl_info_rev3) / sizeof(mimophytbl_info_rev3[0]); ++const u32 mimophytbl_info_sz_rev3_volatile = ++ sizeof(mimophytbl_info_rev3_volatile) / ++ sizeof(mimophytbl_info_rev3_volatile[0]); ++const u32 mimophytbl_info_sz_rev3_volatile1 = ++ sizeof(mimophytbl_info_rev3_volatile1) / ++ sizeof(mimophytbl_info_rev3_volatile1[0]); ++const u32 mimophytbl_info_sz_rev3_volatile2 = ++ sizeof(mimophytbl_info_rev3_volatile2) / ++ sizeof(mimophytbl_info_rev3_volatile2[0]); ++const u32 mimophytbl_info_sz_rev3_volatile3 = ++ sizeof(mimophytbl_info_rev3_volatile3) / ++ sizeof(mimophytbl_info_rev3_volatile3[0]); ++ ++static const u32 tmap_tbl_rev7[] = { ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x000aa888, ++ 0x88880000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00011111, ++ 0x11110000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00088aaa, ++ 0xaaaa0000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xaaa8aaa0, ++ 0x8aaa8aaa, ++ 0xaa8a8a8a, ++ 0x000aaa88, ++ 0x8aaa0000, ++ 0xaaa8a888, ++ 0x8aa88a8a, ++ 0x8a88a888, ++ 0x08080a00, ++ 0x0a08080a, ++ 0x080a0a08, ++ 0x00080808, ++ 0x080a0000, ++ 0x080a0808, ++ 0x080a0808, ++ 0x0a0a0a08, ++ 0xa0a0a0a0, ++ 0x80a0a080, ++ 0x8080a0a0, ++ 0x00008080, ++ 0x80a00000, ++ 0x80a080a0, ++ 0xa080a0a0, ++ 0x8080a0a0, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x99999000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x22000000, ++ 0x2222b222, ++ 0x22222222, ++ 0x222222b2, ++ 0xb2222220, ++ 0x22222222, ++ 0x22d22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333b333, ++ 0x33333333, ++ 0x333333b3, ++ 0xb3333330, ++ 0x33333333, ++ 0x33d33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222a222, ++ 0x22222222, ++ 0x222222a2, ++ 0xa2222220, ++ 0x22222222, ++ 0x22c22222, ++ 0x00000222, ++ 0x99b99b00, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb99, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x22222200, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0x22222222, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x11111111, ++ 0xf1111111, ++ 0x11111111, ++ 0x11f11111, ++ 0x01111111, ++ 0xbb9bb900, ++ 0xb9b9bb99, ++ 0xb99bbbbb, ++ 0xbbbb9b9b, ++ 0xb9bb99bb, ++ 0xb99999b9, ++ 0xb9b9b99b, ++ 0x00000bbb, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88aa, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x0a888aaa, ++ 0xaa000000, ++ 0xa8a8aa88, ++ 0xa88aaaaa, ++ 0xaaaa8a8a, ++ 0xa8aa88a0, ++ 0xa88888a8, ++ 0xa8a8a88a, ++ 0x00000aaa, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0xbbbbbb00, ++ 0x999bbbbb, ++ 0x9bb99b9b, ++ 0xb9b9b9bb, ++ 0xb9b99bbb, ++ 0xb9b9b9bb, ++ 0xb9bb9b99, ++ 0x00000999, ++ 0x8a000000, ++ 0xaa88a888, ++ 0xa88888aa, ++ 0xa88a8a88, ++ 0xa88aa88a, ++ 0x88a8aaaa, ++ 0xa8aa8aaa, ++ 0x0888a88a, ++ 0x0b0b0b00, ++ 0x090b0b0b, ++ 0x0b090b0b, ++ 0x0909090b, ++ 0x09090b0b, ++ 0x09090b0b, ++ 0x09090b09, ++ 0x00000909, ++ 0x0a000000, ++ 0x0a080808, ++ 0x080a080a, ++ 0x080a0a08, ++ 0x080a080a, ++ 0x0808080a, ++ 0x0a0a0a08, ++ 0x0808080a, ++ 0xb0b0b000, ++ 0x9090b0b0, ++ 0x90b09090, ++ 0xb0b0b090, ++ 0xb0b090b0, ++ 0x90b0b0b0, ++ 0xb0b09090, ++ 0x00000090, ++ 0x80000000, ++ 0xa080a080, ++ 0xa08080a0, ++ 0xa0808080, ++ 0xa080a080, ++ 0x80a0a0a0, ++ 0xa0a080a0, ++ 0x00a0a0a0, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x11000000, ++ 0x1111f111, ++ 0x11111111, ++ 0x111111f1, ++ 0xf1111110, ++ 0x11111111, ++ 0x11f11111, ++ 0x00000111, ++ 0x33000000, ++ 0x3333f333, ++ 0x33333333, ++ 0x333333f3, ++ 0xf3333330, ++ 0x33333333, ++ 0x33f33333, ++ 0x00000333, ++ 0x22000000, ++ 0x2222f222, ++ 0x22222222, ++ 0x222222f2, ++ 0xf2222220, ++ 0x22222222, ++ 0x22f22222, ++ 0x00000222, ++ 0x99000000, ++ 0x9b9b99bb, ++ 0x9bb99999, ++ 0x9999b9b9, ++ 0x9b99bb90, ++ 0x9bbbbb9b, ++ 0x9b9b9bb9, ++ 0x00000999, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88888000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00aaa888, ++ 0x88a88a00, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x000aa888, ++ 0x88880000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa88, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x08aaa888, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x11000000, ++ 0x1111a111, ++ 0x11111111, ++ 0x111111a1, ++ 0xa1111110, ++ 0x11111111, ++ 0x11c11111, ++ 0x00000111, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x88000000, ++ 0x8a8a88aa, ++ 0x8aa88888, ++ 0x8888a8a8, ++ 0x8a88aa80, ++ 0x8aaaaa8a, ++ 0x8a8a8aa8, ++ 0x00000888, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++const u32 noise_var_tbl_rev7[] = { ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++ 0x020c020c, ++ 0x0000014d, ++}; ++ ++static const u32 papd_comp_epsilon_tbl_core0_rev7[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00016023, ++ 0x00006028, ++ 0x00034036, ++ 0x0003402e, ++ 0x0007203c, ++ 0x0006e037, ++ 0x00070030, ++ 0x0009401f, ++ 0x0009a00f, ++ 0x000b600d, ++ 0x000c8007, ++ 0x000ce007, ++ 0x00101fff, ++ 0x00121ff9, ++ 0x0012e004, ++ 0x0014dffc, ++ 0x0016dff6, ++ 0x0018dfe9, ++ 0x001b3fe5, ++ 0x001c5fd0, ++ 0x001ddfc2, ++ 0x001f1fb6, ++ 0x00207fa4, ++ 0x00219f8f, ++ 0x0022ff7d, ++ 0x00247f6c, ++ 0x0024df5b, ++ 0x00267f4b, ++ 0x0027df3b, ++ 0x0029bf3b, ++ 0x002b5f2f, ++ 0x002d3f2e, ++ 0x002f5f2a, ++ 0x002fff15, ++ 0x00315f0b, ++ 0x0032defa, ++ 0x0033beeb, ++ 0x0034fed9, ++ 0x00353ec5, ++ 0x00361eb0, ++ 0x00363e9b, ++ 0x0036be87, ++ 0x0036be70, ++ 0x0038fe67, ++ 0x0044beb2, ++ 0x00513ef3, ++ 0x00595f11, ++ 0x00669f3d, ++ 0x0078dfdf, ++ 0x00a143aa, ++ 0x01642fff, ++ 0x0162afff, ++ 0x01620fff, ++ 0x0160cfff, ++ 0x015f0fff, ++ 0x015dafff, ++ 0x015bcfff, ++ 0x015bcfff, ++ 0x015b4fff, ++ 0x015acfff, ++ 0x01590fff, ++ 0x0156cfff, ++}; ++ ++static const u32 papd_cal_scalars_tbl_core0_rev7[] = { ++ 0x0b5e002d, ++ 0x0ae2002f, ++ 0x0a3b0032, ++ 0x09a70035, ++ 0x09220038, ++ 0x08ab003b, ++ 0x081f003f, ++ 0x07a20043, ++ 0x07340047, ++ 0x06d2004b, ++ 0x067a004f, ++ 0x06170054, ++ 0x05bf0059, ++ 0x0571005e, ++ 0x051e0064, ++ 0x04d3006a, ++ 0x04910070, ++ 0x044c0077, ++ 0x040f007e, ++ 0x03d90085, ++ 0x03a1008d, ++ 0x036f0095, ++ 0x033d009e, ++ 0x030b00a8, ++ 0x02e000b2, ++ 0x02b900bc, ++ 0x029200c7, ++ 0x026d00d3, ++ 0x024900e0, ++ 0x022900ed, ++ 0x020a00fb, ++ 0x01ec010a, ++ 0x01d20119, ++ 0x01b7012a, ++ 0x019e013c, ++ 0x0188014e, ++ 0x01720162, ++ 0x015d0177, ++ 0x0149018e, ++ 0x013701a5, ++ 0x012601be, ++ 0x011501d8, ++ 0x010601f4, ++ 0x00f70212, ++ 0x00e90231, ++ 0x00dc0253, ++ 0x00d00276, ++ 0x00c4029b, ++ 0x00b902c3, ++ 0x00af02ed, ++ 0x00a50319, ++ 0x009c0348, ++ 0x0093037a, ++ 0x008b03af, ++ 0x008303e6, ++ 0x007c0422, ++ 0x00750460, ++ 0x006e04a3, ++ 0x006804e9, ++ 0x00620533, ++ 0x005d0582, ++ 0x005805d6, ++ 0x0053062e, ++ 0x004e068c, ++}; ++ ++static const u32 papd_comp_epsilon_tbl_core1_rev7[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00016023, ++ 0x00006028, ++ 0x00034036, ++ 0x0003402e, ++ 0x0007203c, ++ 0x0006e037, ++ 0x00070030, ++ 0x0009401f, ++ 0x0009a00f, ++ 0x000b600d, ++ 0x000c8007, ++ 0x000ce007, ++ 0x00101fff, ++ 0x00121ff9, ++ 0x0012e004, ++ 0x0014dffc, ++ 0x0016dff6, ++ 0x0018dfe9, ++ 0x001b3fe5, ++ 0x001c5fd0, ++ 0x001ddfc2, ++ 0x001f1fb6, ++ 0x00207fa4, ++ 0x00219f8f, ++ 0x0022ff7d, ++ 0x00247f6c, ++ 0x0024df5b, ++ 0x00267f4b, ++ 0x0027df3b, ++ 0x0029bf3b, ++ 0x002b5f2f, ++ 0x002d3f2e, ++ 0x002f5f2a, ++ 0x002fff15, ++ 0x00315f0b, ++ 0x0032defa, ++ 0x0033beeb, ++ 0x0034fed9, ++ 0x00353ec5, ++ 0x00361eb0, ++ 0x00363e9b, ++ 0x0036be87, ++ 0x0036be70, ++ 0x0038fe67, ++ 0x0044beb2, ++ 0x00513ef3, ++ 0x00595f11, ++ 0x00669f3d, ++ 0x0078dfdf, ++ 0x00a143aa, ++ 0x01642fff, ++ 0x0162afff, ++ 0x01620fff, ++ 0x0160cfff, ++ 0x015f0fff, ++ 0x015dafff, ++ 0x015bcfff, ++ 0x015bcfff, ++ 0x015b4fff, ++ 0x015acfff, ++ 0x01590fff, ++ 0x0156cfff, ++}; ++ ++static const u32 papd_cal_scalars_tbl_core1_rev7[] = { ++ 0x0b5e002d, ++ 0x0ae2002f, ++ 0x0a3b0032, ++ 0x09a70035, ++ 0x09220038, ++ 0x08ab003b, ++ 0x081f003f, ++ 0x07a20043, ++ 0x07340047, ++ 0x06d2004b, ++ 0x067a004f, ++ 0x06170054, ++ 0x05bf0059, ++ 0x0571005e, ++ 0x051e0064, ++ 0x04d3006a, ++ 0x04910070, ++ 0x044c0077, ++ 0x040f007e, ++ 0x03d90085, ++ 0x03a1008d, ++ 0x036f0095, ++ 0x033d009e, ++ 0x030b00a8, ++ 0x02e000b2, ++ 0x02b900bc, ++ 0x029200c7, ++ 0x026d00d3, ++ 0x024900e0, ++ 0x022900ed, ++ 0x020a00fb, ++ 0x01ec010a, ++ 0x01d20119, ++ 0x01b7012a, ++ 0x019e013c, ++ 0x0188014e, ++ 0x01720162, ++ 0x015d0177, ++ 0x0149018e, ++ 0x013701a5, ++ 0x012601be, ++ 0x011501d8, ++ 0x010601f4, ++ 0x00f70212, ++ 0x00e90231, ++ 0x00dc0253, ++ 0x00d00276, ++ 0x00c4029b, ++ 0x00b902c3, ++ 0x00af02ed, ++ 0x00a50319, ++ 0x009c0348, ++ 0x0093037a, ++ 0x008b03af, ++ 0x008303e6, ++ 0x007c0422, ++ 0x00750460, ++ 0x006e04a3, ++ 0x006804e9, ++ 0x00620533, ++ 0x005d0582, ++ 0x005805d6, ++ 0x0053062e, ++ 0x004e068c, ++}; ++ ++const struct phytbl_info mimophytbl_info_rev7[] = { ++ {&frame_struct_rev3, ++ sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32} ++ , ++ {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]), ++ 11, 0, 16} ++ , ++ {&tmap_tbl_rev7, sizeof(tmap_tbl_rev7) / sizeof(tmap_tbl_rev7[0]), 12, ++ 0, 32} ++ , ++ {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]), ++ 13, 0, 32} ++ , ++ {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]), ++ 14, 0, 32} ++ , ++ {&noise_var_tbl_rev7, ++ sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32} ++ , ++ {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0, ++ 16} ++ , ++ {&tdi_tbl20_ant0_rev3, ++ sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128, ++ 32} ++ , ++ {&tdi_tbl20_ant1_rev3, ++ sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256, ++ 32} ++ , ++ {&tdi_tbl40_ant0_rev3, ++ sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640, ++ 32} ++ , ++ {&tdi_tbl40_ant1_rev3, ++ sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768, ++ 32} ++ , ++ {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]), ++ 20, 0, 32} ++ , ++ {&chanest_tbl_rev3, ++ sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32} ++ , ++ {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]), ++ 24, 0, 8} ++ , ++ {&est_pwr_lut_core0_rev3, ++ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, ++ 0, 8} ++ , ++ {&est_pwr_lut_core1_rev3, ++ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, ++ 0, 8} ++ , ++ {&adj_pwr_lut_core0_rev3, ++ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, ++ 64, 8} ++ , ++ {&adj_pwr_lut_core1_rev3, ++ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, ++ 64, 8} ++ , ++ {&gainctrl_lut_core0_rev3, ++ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), ++ 26, 192, 32} ++ , ++ {&gainctrl_lut_core1_rev3, ++ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), ++ 27, 192, 32} ++ , ++ {&iq_lut_core0_rev3, ++ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} ++ , ++ {&iq_lut_core1_rev3, ++ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} ++ , ++ {&loft_lut_core0_rev3, ++ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, ++ 16} ++ , ++ {&loft_lut_core1_rev3, ++ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, ++ 16} ++ , ++ {&papd_comp_rfpwr_tbl_core0_rev3, ++ sizeof(papd_comp_rfpwr_tbl_core0_rev3) / ++ sizeof(papd_comp_rfpwr_tbl_core0_rev3[0]), 26, 576, 16} ++ , ++ {&papd_comp_rfpwr_tbl_core1_rev3, ++ sizeof(papd_comp_rfpwr_tbl_core1_rev3) / ++ sizeof(papd_comp_rfpwr_tbl_core1_rev3[0]), 27, 576, 16} ++ , ++ {&papd_comp_epsilon_tbl_core0_rev7, ++ sizeof(papd_comp_epsilon_tbl_core0_rev7) / ++ sizeof(papd_comp_epsilon_tbl_core0_rev7[0]), 31, 0, 32} ++ , ++ {&papd_cal_scalars_tbl_core0_rev7, ++ sizeof(papd_cal_scalars_tbl_core0_rev7) / ++ sizeof(papd_cal_scalars_tbl_core0_rev7[0]), 32, 0, 32} ++ , ++ {&papd_comp_epsilon_tbl_core1_rev7, ++ sizeof(papd_comp_epsilon_tbl_core1_rev7) / ++ sizeof(papd_comp_epsilon_tbl_core1_rev7[0]), 33, 0, 32} ++ , ++ {&papd_cal_scalars_tbl_core1_rev7, ++ sizeof(papd_cal_scalars_tbl_core1_rev7) / ++ sizeof(papd_cal_scalars_tbl_core1_rev7[0]), 34, 0, 32} ++ , ++}; ++ ++const u32 mimophytbl_info_sz_rev7 = ++ sizeof(mimophytbl_info_rev7) / sizeof(mimophytbl_info_rev7[0]); ++ ++const struct phytbl_info mimophytbl_info_rev16[] = { ++ {&noise_var_tbl_rev7, ++ sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32} ++ , ++ {&est_pwr_lut_core0_rev3, ++ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, ++ 0, 8} ++ , ++ {&est_pwr_lut_core1_rev3, ++ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, ++ 0, 8} ++ , ++ {&adj_pwr_lut_core0_rev3, ++ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, ++ 64, 8} ++ , ++ {&adj_pwr_lut_core1_rev3, ++ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, ++ 64, 8} ++ , ++ {&gainctrl_lut_core0_rev3, ++ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), ++ 26, 192, 32} ++ , ++ {&gainctrl_lut_core1_rev3, ++ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), ++ 27, 192, 32} ++ , ++ {&iq_lut_core0_rev3, ++ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} ++ , ++ {&iq_lut_core1_rev3, ++ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} ++ , ++ {&loft_lut_core0_rev3, ++ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, ++ 16} ++ , ++ {&loft_lut_core1_rev3, ++ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, ++ 16} ++ , ++}; ++ ++const u32 mimophytbl_info_sz_rev16 = ++ sizeof(mimophytbl_info_rev16) / sizeof(mimophytbl_info_rev16[0]); +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h.orig 2011-11-09 13:46:58.282800170 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h 2011-11-09 13:47:17.040565666 -0500 +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++#define ANT_SWCTRL_TBL_REV3_IDX (0) ++ ++#include ++#include "phy_int.h" ++ ++extern const struct phytbl_info mimophytbl_info_rev0[], ++ mimophytbl_info_rev0_volatile[]; ++ ++extern const u32 mimophytbl_info_sz_rev0, ++ mimophytbl_info_sz_rev0_volatile; ++ ++extern const struct phytbl_info mimophytbl_info_rev3[], ++ mimophytbl_info_rev3_volatile[], ++ mimophytbl_info_rev3_volatile1[], ++ mimophytbl_info_rev3_volatile2[], ++ mimophytbl_info_rev3_volatile3[]; ++ ++extern const u32 mimophytbl_info_sz_rev3, ++ mimophytbl_info_sz_rev3_volatile, ++ mimophytbl_info_sz_rev3_volatile1, ++ mimophytbl_info_sz_rev3_volatile2, ++ mimophytbl_info_sz_rev3_volatile3; ++ ++extern const u32 noise_var_tbl_rev3[]; ++ ++extern const struct phytbl_info mimophytbl_info_rev7[]; ++ ++extern const u32 mimophytbl_info_sz_rev7; ++ ++extern const u32 noise_var_tbl_rev7[]; ++ ++extern const struct phytbl_info mimophytbl_info_rev16[]; ++ ++extern const u32 mimophytbl_info_sz_rev16; +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c.orig 2011-11-09 13:46:58.282800170 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c 2011-11-09 13:47:17.040565666 -0500 +@@ -0,0 +1,225 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/* ++ * This is "two-way" interface, acting as the SHIM layer between driver ++ * and PHY layer. The driver can optionally call this translation layer ++ * to do some preprocessing, then reach PHY. On the PHY->driver direction, ++ * all calls go through this layer since PHY doesn't have access to the ++ * driver's brcms_hardware pointer. ++ */ ++#include ++#include ++ ++#include "main.h" ++#include "mac80211_if.h" ++#include "phy_shim.h" ++ ++/* PHY SHIM module specific state */ ++struct phy_shim_info { ++ struct brcms_hardware *wlc_hw; /* pointer to main wlc_hw structure */ ++ struct brcms_c_info *wlc; /* pointer to main wlc structure */ ++ struct brcms_info *wl; /* pointer to os-specific private state */ ++}; ++ ++struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, ++ struct brcms_info *wl, ++ struct brcms_c_info *wlc) { ++ struct phy_shim_info *physhim = NULL; ++ ++ physhim = kzalloc(sizeof(struct phy_shim_info), GFP_ATOMIC); ++ if (!physhim) ++ return NULL; ++ ++ physhim->wlc_hw = wlc_hw; ++ physhim->wlc = wlc; ++ physhim->wl = wl; ++ ++ return physhim; ++} ++ ++void wlc_phy_shim_detach(struct phy_shim_info *physhim) ++{ ++ kfree(physhim); ++} ++ ++struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, ++ void (*fn)(struct brcms_phy *pi), ++ void *arg, const char *name) ++{ ++ return (struct wlapi_timer *) ++ brcms_init_timer(physhim->wl, (void (*)(void *))fn, ++ arg, name); ++} ++ ++void wlapi_free_timer(struct wlapi_timer *t) ++{ ++ brcms_free_timer((struct brcms_timer *)t); ++} ++ ++void ++wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic) ++{ ++ brcms_add_timer((struct brcms_timer *)t, ms, periodic); ++} ++ ++bool wlapi_del_timer(struct wlapi_timer *t) ++{ ++ return brcms_del_timer((struct brcms_timer *)t); ++} ++ ++void wlapi_intrson(struct phy_shim_info *physhim) ++{ ++ brcms_intrson(physhim->wl); ++} ++ ++u32 wlapi_intrsoff(struct phy_shim_info *physhim) ++{ ++ return brcms_intrsoff(physhim->wl); ++} ++ ++void wlapi_intrsrestore(struct phy_shim_info *physhim, u32 macintmask) ++{ ++ brcms_intrsrestore(physhim->wl, macintmask); ++} ++ ++void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, u16 v) ++{ ++ brcms_b_write_shm(physhim->wlc_hw, offset, v); ++} ++ ++u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset) ++{ ++ return brcms_b_read_shm(physhim->wlc_hw, offset); ++} ++ ++void ++wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, u16 mask, ++ u16 val, int bands) ++{ ++ brcms_b_mhf(physhim->wlc_hw, idx, mask, val, bands); ++} ++ ++void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags) ++{ ++ brcms_b_corereset(physhim->wlc_hw, flags); ++} ++ ++void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim) ++{ ++ brcms_c_suspend_mac_and_wait(physhim->wlc); ++} ++ ++void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode) ++{ ++ brcms_b_switch_macfreq(physhim->wlc_hw, spurmode); ++} ++ ++void wlapi_enable_mac(struct phy_shim_info *physhim) ++{ ++ brcms_c_enable_mac(physhim->wlc); ++} ++ ++void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, u32 val) ++{ ++ brcms_b_mctrl(physhim->wlc_hw, mask, val); ++} ++ ++void wlapi_bmac_phy_reset(struct phy_shim_info *physhim) ++{ ++ brcms_b_phy_reset(physhim->wlc_hw); ++} ++ ++void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw) ++{ ++ brcms_b_bw_set(physhim->wlc_hw, bw); ++} ++ ++u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim) ++{ ++ return brcms_b_get_txant(physhim->wlc_hw); ++} ++ ++void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk) ++{ ++ brcms_b_phyclk_fgc(physhim->wlc_hw, clk); ++} ++ ++void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk) ++{ ++ brcms_b_macphyclk_set(physhim->wlc_hw, clk); ++} ++ ++void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on) ++{ ++ brcms_b_core_phypll_ctl(physhim->wlc_hw, on); ++} ++ ++void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim) ++{ ++ brcms_b_core_phypll_reset(physhim->wlc_hw); ++} ++ ++void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info *physhim) ++{ ++ brcms_c_ucode_wake_override_set(physhim->wlc_hw, ++ BRCMS_WAKE_OVERRIDE_PHYREG); ++} ++ ++void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info *physhim) ++{ ++ brcms_c_ucode_wake_override_clear(physhim->wlc_hw, ++ BRCMS_WAKE_OVERRIDE_PHYREG); ++} ++ ++void ++wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int offset, ++ int len, void *buf) ++{ ++ brcms_b_write_template_ram(physhim->wlc_hw, offset, len, buf); ++} ++ ++u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, u8 rate) ++{ ++ return brcms_b_rate_shm_offset(physhim->wlc_hw, rate); ++} ++ ++void wlapi_ucode_sample_init(struct phy_shim_info *physhim) ++{ ++} ++ ++void ++wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint offset, void *buf, ++ int len, u32 sel) ++{ ++ brcms_b_copyfrom_objmem(physhim->wlc_hw, offset, buf, len, sel); ++} ++ ++void ++wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf, ++ int l, u32 sel) ++{ ++ brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel); ++} ++ ++char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id) ++{ ++ return getvar(physhim->wlc_hw->sih, id); ++} ++int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id) ++{ ++ return getintvar(physhim->wlc_hw->sih, id); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h.orig 2011-11-09 13:46:58.282800170 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h 2011-11-09 13:47:17.041565653 -0500 +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * 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. ++ */ ++ ++/* ++ * phy_shim.h: stuff defined in phy_shim.c and included only by the phy ++ */ ++ ++#ifndef _BRCM_PHY_SHIM_H_ ++#define _BRCM_PHY_SHIM_H_ ++ ++#include "types.h" ++ ++#define RADAR_TYPE_NONE 0 /* Radar type None */ ++#define RADAR_TYPE_ETSI_1 1 /* ETSI 1 Radar type */ ++#define RADAR_TYPE_ETSI_2 2 /* ETSI 2 Radar type */ ++#define RADAR_TYPE_ETSI_3 3 /* ETSI 3 Radar type */ ++#define RADAR_TYPE_ITU_E 4 /* ITU E Radar type */ ++#define RADAR_TYPE_ITU_K 5 /* ITU K Radar type */ ++#define RADAR_TYPE_UNCLASSIFIED 6 /* Unclassified Radar type */ ++#define RADAR_TYPE_BIN5 7 /* long pulse radar type */ ++#define RADAR_TYPE_STG2 8 /* staggered-2 radar */ ++#define RADAR_TYPE_STG3 9 /* staggered-3 radar */ ++#define RADAR_TYPE_FRA 10 /* French radar */ ++ ++/* French radar pulse widths */ ++#define FRA_T1_20MHZ 52770 ++#define FRA_T2_20MHZ 61538 ++#define FRA_T3_20MHZ 66002 ++#define FRA_T1_40MHZ 105541 ++#define FRA_T2_40MHZ 123077 ++#define FRA_T3_40MHZ 132004 ++#define FRA_ERR_20MHZ 60 ++#define FRA_ERR_40MHZ 120 ++ ++#define ANTSEL_NA 0 /* No boardlevel selection available */ ++#define ANTSEL_2x4 1 /* 2x4 boardlevel selection available */ ++#define ANTSEL_2x3 2 /* 2x3 CB2 boardlevel selection available */ ++ ++/* Rx Antenna diversity control values */ ++#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */ ++#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */ ++#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */ ++#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */ ++#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */ ++#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */ ++ ++#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ ++#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ ++#define WL_ANT_IDX_1 0 /* antenna index 1 */ ++#define WL_ANT_IDX_2 1 /* antenna index 2 */ ++ ++/* values for n_preamble_type */ ++#define BRCMS_N_PREAMBLE_MIXEDMODE 0 ++#define BRCMS_N_PREAMBLE_GF 1 ++#define BRCMS_N_PREAMBLE_GF_BRCM 2 ++ ++#define WL_TX_POWER_RATES_LEGACY 45 ++#define WL_TX_POWER_MCS20_FIRST 12 ++#define WL_TX_POWER_MCS20_NUM 16 ++#define WL_TX_POWER_MCS40_FIRST 28 ++#define WL_TX_POWER_MCS40_NUM 17 ++ ++ ++#define WL_TX_POWER_RATES 101 ++#define WL_TX_POWER_CCK_FIRST 0 ++#define WL_TX_POWER_CCK_NUM 4 ++/* Index for first 20MHz OFDM SISO rate */ ++#define WL_TX_POWER_OFDM_FIRST 4 ++/* Index for first 20MHz OFDM CDD rate */ ++#define WL_TX_POWER_OFDM20_CDD_FIRST 12 ++/* Index for first 40MHz OFDM SISO rate */ ++#define WL_TX_POWER_OFDM40_SISO_FIRST 52 ++/* Index for first 40MHz OFDM CDD rate */ ++#define WL_TX_POWER_OFDM40_CDD_FIRST 60 ++#define WL_TX_POWER_OFDM_NUM 8 ++/* Index for first 20MHz MCS SISO rate */ ++#define WL_TX_POWER_MCS20_SISO_FIRST 20 ++/* Index for first 20MHz MCS CDD rate */ ++#define WL_TX_POWER_MCS20_CDD_FIRST 28 ++/* Index for first 20MHz MCS STBC rate */ ++#define WL_TX_POWER_MCS20_STBC_FIRST 36 ++/* Index for first 20MHz MCS SDM rate */ ++#define WL_TX_POWER_MCS20_SDM_FIRST 44 ++/* Index for first 40MHz MCS SISO rate */ ++#define WL_TX_POWER_MCS40_SISO_FIRST 68 ++/* Index for first 40MHz MCS CDD rate */ ++#define WL_TX_POWER_MCS40_CDD_FIRST 76 ++/* Index for first 40MHz MCS STBC rate */ ++#define WL_TX_POWER_MCS40_STBC_FIRST 84 ++/* Index for first 40MHz MCS SDM rate */ ++#define WL_TX_POWER_MCS40_SDM_FIRST 92 ++#define WL_TX_POWER_MCS_1_STREAM_NUM 8 ++#define WL_TX_POWER_MCS_2_STREAM_NUM 8 ++/* Index for 40MHz rate MCS 32 */ ++#define WL_TX_POWER_MCS_32 100 ++#define WL_TX_POWER_MCS_32_NUM 1 ++ ++/* sslpnphy specifics */ ++/* Index for first 20MHz MCS SISO rate */ ++#define WL_TX_POWER_MCS20_SISO_FIRST_SSN 12 ++ ++/* struct tx_power::flags bits */ ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++ ++/* values to force tx/rx chain */ ++#define BRCMS_N_TXRX_CHAIN0 0 ++#define BRCMS_N_TXRX_CHAIN1 1 ++ ++struct brcms_phy; ++ ++extern struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, ++ struct brcms_info *wl, ++ struct brcms_c_info *wlc); ++extern void wlc_phy_shim_detach(struct phy_shim_info *physhim); ++ ++/* PHY to WL utility functions */ ++extern struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, ++ void (*fn) (struct brcms_phy *pi), ++ void *arg, const char *name); ++extern void wlapi_free_timer(struct wlapi_timer *t); ++extern void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); ++extern bool wlapi_del_timer(struct wlapi_timer *t); ++extern void wlapi_intrson(struct phy_shim_info *physhim); ++extern u32 wlapi_intrsoff(struct phy_shim_info *physhim); ++extern void wlapi_intrsrestore(struct phy_shim_info *physhim, ++ u32 macintmask); ++ ++extern void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, ++ u16 v); ++extern u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset); ++extern void wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, ++ u16 mask, u16 val, int bands); ++extern void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags); ++extern void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim); ++extern void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode); ++extern void wlapi_enable_mac(struct phy_shim_info *physhim); ++extern void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, ++ u32 val); ++extern void wlapi_bmac_phy_reset(struct phy_shim_info *physhim); ++extern void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw); ++extern void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk); ++extern void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk); ++extern void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on); ++extern void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim); ++extern void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info * ++ physhim); ++extern void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info * ++ physhim); ++extern void wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int o, ++ int len, void *buf); ++extern u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, ++ u8 rate); ++extern void wlapi_ucode_sample_init(struct phy_shim_info *physhim); ++extern void wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint, ++ void *buf, int, u32 sel); ++extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint, ++ const void *buf, int, u32); ++ ++extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim, ++ u32 phy_mode); ++extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim); ++extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id); ++extern int wlapi_getintvar(struct phy_shim_info *physhim, ++ enum brcms_srom_id id); ++ ++#endif /* _BRCM_PHY_SHIM_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.c.orig 2011-11-09 13:46:58.283800157 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.c 2011-11-09 13:47:17.041565653 -0500 +@@ -0,0 +1,458 @@ ++/* ++ * Copyright (c) 2011 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include "pub.h" ++#include "aiutils.h" ++#include "pmu.h" ++ ++/* ++ * external LPO crystal frequency ++ */ ++#define EXT_ILP_HZ 32768 ++ ++/* ++ * Duration for ILP clock frequency measurment in milliseconds ++ * ++ * remark: 1000 must be an integer multiple of this duration ++ */ ++#define ILP_CALC_DUR 10 ++ ++/* Fields in pmucontrol */ ++#define PCTL_ILP_DIV_MASK 0xffff0000 ++#define PCTL_ILP_DIV_SHIFT 16 ++#define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */ ++#define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */ ++#define PCTL_HT_REQ_EN 0x00000100 ++#define PCTL_ALP_REQ_EN 0x00000080 ++#define PCTL_XTALFREQ_MASK 0x0000007c ++#define PCTL_XTALFREQ_SHIFT 2 ++#define PCTL_ILP_DIV_EN 0x00000002 ++#define PCTL_LPO_SEL 0x00000001 ++ ++/* ILP clock */ ++#define ILP_CLOCK 32000 ++ ++/* ALP clock on pre-PMU chips */ ++#define ALP_CLOCK 20000000 ++ ++/* pmustatus */ ++#define PST_EXTLPOAVAIL 0x0100 ++#define PST_WDRESET 0x0080 ++#define PST_INTPEND 0x0040 ++#define PST_SBCLKST 0x0030 ++#define PST_SBCLKST_ILP 0x0010 ++#define PST_SBCLKST_ALP 0x0020 ++#define PST_SBCLKST_HT 0x0030 ++#define PST_ALPAVAIL 0x0008 ++#define PST_HTAVAIL 0x0004 ++#define PST_RESINIT 0x0003 ++ ++/* PMU resource bit position */ ++#define PMURES_BIT(bit) (1 << (bit)) ++ ++/* PMU corerev and chip specific PLL controls. ++ * PMU_PLL_XX where is PMU corerev and is an arbitrary ++ * number to differentiate different PLLs controlled by the same PMU rev. ++ */ ++/* pllcontrol registers: ++ * ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, ++ * p1div, p2div, _bypass_sdmod ++ */ ++#define PMU1_PLL0_PLLCTL0 0 ++#define PMU1_PLL0_PLLCTL1 1 ++#define PMU1_PLL0_PLLCTL2 2 ++#define PMU1_PLL0_PLLCTL3 3 ++#define PMU1_PLL0_PLLCTL4 4 ++#define PMU1_PLL0_PLLCTL5 5 ++ ++/* pmu XtalFreqRatio */ ++#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF ++#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 ++#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 ++ ++/* 4313 resources */ ++#define RES4313_BB_PU_RSRC 0 ++#define RES4313_ILP_REQ_RSRC 1 ++#define RES4313_XTAL_PU_RSRC 2 ++#define RES4313_ALP_AVAIL_RSRC 3 ++#define RES4313_RADIO_PU_RSRC 4 ++#define RES4313_BG_PU_RSRC 5 ++#define RES4313_VREG1P4_PU_RSRC 6 ++#define RES4313_AFE_PWRSW_RSRC 7 ++#define RES4313_RX_PWRSW_RSRC 8 ++#define RES4313_TX_PWRSW_RSRC 9 ++#define RES4313_BB_PWRSW_RSRC 10 ++#define RES4313_SYNTH_PWRSW_RSRC 11 ++#define RES4313_MISC_PWRSW_RSRC 12 ++#define RES4313_BB_PLL_PWRSW_RSRC 13 ++#define RES4313_HT_AVAIL_RSRC 14 ++#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 ++ ++/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */ ++static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) ++{ ++ u32 min_mask = 0, max_mask = 0; ++ uint rsrcs; ++ ++ /* # resources */ ++ rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; ++ ++ /* determine min/max rsrc masks */ ++ switch (sih->chip) { ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ /* ??? */ ++ break; ++ ++ case BCM4313_CHIP_ID: ++ min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) | ++ PMURES_BIT(RES4313_XTAL_PU_RSRC) | ++ PMURES_BIT(RES4313_ALP_AVAIL_RSRC) | ++ PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC); ++ max_mask = 0xffff; ++ break; ++ default: ++ break; ++ } ++ ++ *pmin = min_mask; ++ *pmax = max_mask; ++} ++ ++static void ++si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc, ++ u8 spuravoid) ++{ ++ u32 tmp = 0; ++ ++ switch (sih->chip) { ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ if (spuravoid == 1) { ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); ++ W_REG(&cc->pllcontrol_data, 0x11500010); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); ++ W_REG(&cc->pllcontrol_data, 0x000C0C06); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); ++ W_REG(&cc->pllcontrol_data, 0x0F600a08); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); ++ W_REG(&cc->pllcontrol_data, 0x00000000); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); ++ W_REG(&cc->pllcontrol_data, 0x2001E920); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); ++ W_REG(&cc->pllcontrol_data, 0x88888815); ++ } else { ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); ++ W_REG(&cc->pllcontrol_data, 0x11100010); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); ++ W_REG(&cc->pllcontrol_data, 0x000c0c06); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); ++ W_REG(&cc->pllcontrol_data, 0x03000a08); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); ++ W_REG(&cc->pllcontrol_data, 0x00000000); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); ++ W_REG(&cc->pllcontrol_data, 0x200005c0); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); ++ W_REG(&cc->pllcontrol_data, 0x88888815); ++ } ++ tmp = 1 << 10; ++ break; ++ ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); ++ W_REG(&cc->pllcontrol_data, 0x11100008); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); ++ W_REG(&cc->pllcontrol_data, 0x0c000c06); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); ++ W_REG(&cc->pllcontrol_data, 0x03000a08); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); ++ W_REG(&cc->pllcontrol_data, 0x00000000); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); ++ W_REG(&cc->pllcontrol_data, 0x200005c0); ++ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); ++ W_REG(&cc->pllcontrol_data, 0x88888855); ++ ++ tmp = 1 << 10; ++ break; ++ ++ default: ++ /* bail out */ ++ return; ++ } ++ ++ tmp |= R_REG(&cc->pmucontrol); ++ W_REG(&cc->pmucontrol, tmp); ++} ++ ++u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) ++{ ++ uint delay = PMU_MAX_TRANSITION_DLY; ++ ++ switch (sih->chip) { ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ case BCM4313_CHIP_ID: ++ delay = 3700; ++ break; ++ default: ++ break; ++ } ++ ++ return (u16) delay; ++} ++ ++void si_pmu_sprom_enable(struct si_pub *sih, bool enable) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ ++ /* Remember original core before switch to chipc */ ++ origidx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* Read/write a chipcontrol reg */ ++u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) ++{ ++ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr), ++ ~0, reg); ++ return ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, chipcontrol_data), mask, ++ val); ++} ++ ++/* Read/write a regcontrol reg */ ++u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) ++{ ++ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr), ++ ~0, reg); ++ return ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, regcontrol_data), mask, ++ val); ++} ++ ++/* Read/write a pllcontrol reg */ ++u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) ++{ ++ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr), ++ ~0, reg); ++ return ai_corereg(sih, SI_CC_IDX, ++ offsetof(struct chipcregs, pllcontrol_data), mask, ++ val); ++} ++ ++/* PMU PLL update */ ++void si_pmu_pllupd(struct si_pub *sih) ++{ ++ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol), ++ PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD); ++} ++ ++/* query alp/xtal clock frequency */ ++u32 si_pmu_alp_clock(struct si_pub *sih) ++{ ++ u32 clock = ALP_CLOCK; ++ ++ /* bail out with default */ ++ if (!(sih->cccaps & CC_CAP_PMU)) ++ return clock; ++ ++ switch (sih->chip) { ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ case BCM4313_CHIP_ID: ++ /* always 20Mhz */ ++ clock = 20000 * 1000; ++ break; ++ default: ++ break; ++ } ++ ++ return clock; ++} ++ ++void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx, intr_val; ++ ++ /* Remember original core before switch to chipc */ ++ cc = (struct chipcregs __iomem *) ++ ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); ++ ++ /* update the pll changes */ ++ si_pmu_spuravoid_pllupdate(sih, cc, spuravoid); ++ ++ /* Return to original core */ ++ ai_restore_core(sih, origidx, intr_val); ++} ++ ++/* initialize PMU */ ++void si_pmu_init(struct si_pub *sih) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ ++ /* Remember original core before switch to chipc */ ++ origidx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ if (sih->pmurev == 1) ++ AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT); ++ else if (sih->pmurev >= 2) ++ OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT); ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* initialize PMU chip controls and other chip level stuff */ ++void si_pmu_chip_init(struct si_pub *sih) ++{ ++ uint origidx; ++ ++ /* Gate off SPROM clock and chip select signals */ ++ si_pmu_sprom_enable(sih, false); ++ ++ /* Remember original core */ ++ origidx = ai_coreidx(sih); ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* initialize PMU switch/regulators */ ++void si_pmu_swreg_init(struct si_pub *sih) ++{ ++} ++ ++/* initialize PLL */ ++void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ ++ /* Remember original core before switch to chipc */ ++ origidx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ switch (sih->chip) { ++ case BCM4313_CHIP_ID: ++ case BCM43224_CHIP_ID: ++ case BCM43225_CHIP_ID: ++ /* ??? */ ++ break; ++ default: ++ break; ++ } ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++} ++ ++/* initialize PMU resources */ ++void si_pmu_res_init(struct si_pub *sih) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ u32 min_mask = 0, max_mask = 0; ++ ++ /* Remember original core before switch to chipc */ ++ origidx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ /* Determine min/max rsrc masks */ ++ si_pmu_res_masks(sih, &min_mask, &max_mask); ++ ++ /* It is required to program max_mask first and then min_mask */ ++ ++ /* Program max resource mask */ ++ ++ if (max_mask) ++ W_REG(&cc->max_res_mask, max_mask); ++ ++ /* Program min resource mask */ ++ ++ if (min_mask) ++ W_REG(&cc->min_res_mask, min_mask); ++ ++ /* Add some delay; allow resources to come up and settle. */ ++ mdelay(2); ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++} ++ ++u32 si_pmu_measure_alpclk(struct si_pub *sih) ++{ ++ struct chipcregs __iomem *cc; ++ uint origidx; ++ u32 alp_khz; ++ ++ if (sih->pmurev < 10) ++ return 0; ++ ++ /* Remember original core before switch to chipc */ ++ origidx = ai_coreidx(sih); ++ cc = ai_setcoreidx(sih, SI_CC_IDX); ++ ++ if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) { ++ u32 ilp_ctr, alp_hz; ++ ++ /* ++ * Enable the reg to measure the freq, ++ * in case it was disabled before ++ */ ++ W_REG(&cc->pmu_xtalfreq, ++ 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); ++ ++ /* Delay for well over 4 ILP clocks */ ++ udelay(1000); ++ ++ /* Read the latched number of ALP ticks per 4 ILP ticks */ ++ ilp_ctr = ++ R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK; ++ ++ /* ++ * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT ++ * bit to save power ++ */ ++ W_REG(&cc->pmu_xtalfreq, 0); ++ ++ /* Calculate ALP frequency */ ++ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; ++ ++ /* ++ * Round to nearest 100KHz, and at ++ * the same time convert to KHz ++ */ ++ alp_khz = (alp_hz + 50000) / 100000 * 100; ++ } else ++ alp_khz = 0; ++ ++ /* Return to original core */ ++ ai_setcoreidx(sih, origidx); ++ ++ return alp_khz; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.h.orig 2011-11-09 13:46:58.283800157 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pmu.h 2011-11-09 13:47:17.041565653 -0500 +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#ifndef _BRCM_PMU_H_ ++#define _BRCM_PMU_H_ ++ ++#include "types.h" ++ ++extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih); ++extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable); ++extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); ++extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); ++extern u32 si_pmu_alp_clock(struct si_pub *sih); ++extern void si_pmu_pllupd(struct si_pub *sih); ++extern void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid); ++extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); ++extern void si_pmu_init(struct si_pub *sih); ++extern void si_pmu_chip_init(struct si_pub *sih); ++extern void si_pmu_pll_init(struct si_pub *sih, u32 xtalfreq); ++extern void si_pmu_res_init(struct si_pub *sih); ++extern void si_pmu_swreg_init(struct si_pub *sih); ++extern u32 si_pmu_measure_alpclk(struct si_pub *sih); ++ ++#endif /* _BRCM_PMU_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pub.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pub.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pub.h.orig 2011-11-09 13:46:58.283800157 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/pub.h 2011-11-09 13:47:17.042565640 -0500 +@@ -0,0 +1,634 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_PUB_H_ ++#define _BRCM_PUB_H_ ++ ++#include ++#include "types.h" ++#include "defs.h" ++ ++enum brcms_srom_id { ++ BRCMS_SROM_NULL, ++ BRCMS_SROM_CONT, ++ BRCMS_SROM_AA2G, ++ BRCMS_SROM_AA5G, ++ BRCMS_SROM_AG0, ++ BRCMS_SROM_AG1, ++ BRCMS_SROM_AG2, ++ BRCMS_SROM_AG3, ++ BRCMS_SROM_ANTSWCTL2G, ++ BRCMS_SROM_ANTSWCTL5G, ++ BRCMS_SROM_ANTSWITCH, ++ BRCMS_SROM_BOARDFLAGS2, ++ BRCMS_SROM_BOARDFLAGS, ++ BRCMS_SROM_BOARDNUM, ++ BRCMS_SROM_BOARDREV, ++ BRCMS_SROM_BOARDTYPE, ++ BRCMS_SROM_BW40PO, ++ BRCMS_SROM_BWDUPPO, ++ BRCMS_SROM_BXA2G, ++ BRCMS_SROM_BXA5G, ++ BRCMS_SROM_CC, ++ BRCMS_SROM_CCK2GPO, ++ BRCMS_SROM_CCKBW202GPO, ++ BRCMS_SROM_CCKBW20UL2GPO, ++ BRCMS_SROM_CCODE, ++ BRCMS_SROM_CDDPO, ++ BRCMS_SROM_DEVID, ++ BRCMS_SROM_ET1MACADDR, ++ BRCMS_SROM_EXTPAGAIN2G, ++ BRCMS_SROM_EXTPAGAIN5G, ++ BRCMS_SROM_FREQOFFSET_CORR, ++ BRCMS_SROM_HW_IQCAL_EN, ++ BRCMS_SROM_IL0MACADDR, ++ BRCMS_SROM_IQCAL_SWP_DIS, ++ BRCMS_SROM_LEDBH0, ++ BRCMS_SROM_LEDBH1, ++ BRCMS_SROM_LEDBH2, ++ BRCMS_SROM_LEDBH3, ++ BRCMS_SROM_LEDDC, ++ BRCMS_SROM_LEGOFDM40DUPPO, ++ BRCMS_SROM_LEGOFDMBW202GPO, ++ BRCMS_SROM_LEGOFDMBW205GHPO, ++ BRCMS_SROM_LEGOFDMBW205GLPO, ++ BRCMS_SROM_LEGOFDMBW205GMPO, ++ BRCMS_SROM_LEGOFDMBW20UL2GPO, ++ BRCMS_SROM_LEGOFDMBW20UL5GHPO, ++ BRCMS_SROM_LEGOFDMBW20UL5GLPO, ++ BRCMS_SROM_LEGOFDMBW20UL5GMPO, ++ BRCMS_SROM_MACADDR, ++ BRCMS_SROM_MCS2GPO0, ++ BRCMS_SROM_MCS2GPO1, ++ BRCMS_SROM_MCS2GPO2, ++ BRCMS_SROM_MCS2GPO3, ++ BRCMS_SROM_MCS2GPO4, ++ BRCMS_SROM_MCS2GPO5, ++ BRCMS_SROM_MCS2GPO6, ++ BRCMS_SROM_MCS2GPO7, ++ BRCMS_SROM_MCS32PO, ++ BRCMS_SROM_MCS5GHPO0, ++ BRCMS_SROM_MCS5GHPO1, ++ BRCMS_SROM_MCS5GHPO2, ++ BRCMS_SROM_MCS5GHPO3, ++ BRCMS_SROM_MCS5GHPO4, ++ BRCMS_SROM_MCS5GHPO5, ++ BRCMS_SROM_MCS5GHPO6, ++ BRCMS_SROM_MCS5GHPO7, ++ BRCMS_SROM_MCS5GLPO0, ++ BRCMS_SROM_MCS5GLPO1, ++ BRCMS_SROM_MCS5GLPO2, ++ BRCMS_SROM_MCS5GLPO3, ++ BRCMS_SROM_MCS5GLPO4, ++ BRCMS_SROM_MCS5GLPO5, ++ BRCMS_SROM_MCS5GLPO6, ++ BRCMS_SROM_MCS5GLPO7, ++ BRCMS_SROM_MCS5GPO0, ++ BRCMS_SROM_MCS5GPO1, ++ BRCMS_SROM_MCS5GPO2, ++ BRCMS_SROM_MCS5GPO3, ++ BRCMS_SROM_MCS5GPO4, ++ BRCMS_SROM_MCS5GPO5, ++ BRCMS_SROM_MCS5GPO6, ++ BRCMS_SROM_MCS5GPO7, ++ BRCMS_SROM_MCSBW202GPO, ++ BRCMS_SROM_MCSBW205GHPO, ++ BRCMS_SROM_MCSBW205GLPO, ++ BRCMS_SROM_MCSBW205GMPO, ++ BRCMS_SROM_MCSBW20UL2GPO, ++ BRCMS_SROM_MCSBW20UL5GHPO, ++ BRCMS_SROM_MCSBW20UL5GLPO, ++ BRCMS_SROM_MCSBW20UL5GMPO, ++ BRCMS_SROM_MCSBW402GPO, ++ BRCMS_SROM_MCSBW405GHPO, ++ BRCMS_SROM_MCSBW405GLPO, ++ BRCMS_SROM_MCSBW405GMPO, ++ BRCMS_SROM_MEASPOWER, ++ BRCMS_SROM_OFDM2GPO, ++ BRCMS_SROM_OFDM5GHPO, ++ BRCMS_SROM_OFDM5GLPO, ++ BRCMS_SROM_OFDM5GPO, ++ BRCMS_SROM_OPO, ++ BRCMS_SROM_PA0B0, ++ BRCMS_SROM_PA0B1, ++ BRCMS_SROM_PA0B2, ++ BRCMS_SROM_PA0ITSSIT, ++ BRCMS_SROM_PA0MAXPWR, ++ BRCMS_SROM_PA1B0, ++ BRCMS_SROM_PA1B1, ++ BRCMS_SROM_PA1B2, ++ BRCMS_SROM_PA1HIB0, ++ BRCMS_SROM_PA1HIB1, ++ BRCMS_SROM_PA1HIB2, ++ BRCMS_SROM_PA1HIMAXPWR, ++ BRCMS_SROM_PA1ITSSIT, ++ BRCMS_SROM_PA1LOB0, ++ BRCMS_SROM_PA1LOB1, ++ BRCMS_SROM_PA1LOB2, ++ BRCMS_SROM_PA1LOMAXPWR, ++ BRCMS_SROM_PA1MAXPWR, ++ BRCMS_SROM_PDETRANGE2G, ++ BRCMS_SROM_PDETRANGE5G, ++ BRCMS_SROM_PHYCAL_TEMPDELTA, ++ BRCMS_SROM_RAWTEMPSENSE, ++ BRCMS_SROM_REGREV, ++ BRCMS_SROM_REV, ++ BRCMS_SROM_RSSISAV2G, ++ BRCMS_SROM_RSSISAV5G, ++ BRCMS_SROM_RSSISMC2G, ++ BRCMS_SROM_RSSISMC5G, ++ BRCMS_SROM_RSSISMF2G, ++ BRCMS_SROM_RSSISMF5G, ++ BRCMS_SROM_RXCHAIN, ++ BRCMS_SROM_RXPO2G, ++ BRCMS_SROM_RXPO5G, ++ BRCMS_SROM_STBCPO, ++ BRCMS_SROM_TEMPCORRX, ++ BRCMS_SROM_TEMPOFFSET, ++ BRCMS_SROM_TEMPSENSE_OPTION, ++ BRCMS_SROM_TEMPSENSE_SLOPE, ++ BRCMS_SROM_TEMPTHRESH, ++ BRCMS_SROM_TRI2G, ++ BRCMS_SROM_TRI5GH, ++ BRCMS_SROM_TRI5GL, ++ BRCMS_SROM_TRI5G, ++ BRCMS_SROM_TRISO2G, ++ BRCMS_SROM_TRISO5G, ++ BRCMS_SROM_TSSIPOS2G, ++ BRCMS_SROM_TSSIPOS5G, ++ BRCMS_SROM_TXCHAIN, ++ BRCMS_SROM_TXPID2GA0, ++ BRCMS_SROM_TXPID2GA1, ++ BRCMS_SROM_TXPID2GA2, ++ BRCMS_SROM_TXPID2GA3, ++ BRCMS_SROM_TXPID5GA0, ++ BRCMS_SROM_TXPID5GA1, ++ BRCMS_SROM_TXPID5GA2, ++ BRCMS_SROM_TXPID5GA3, ++ BRCMS_SROM_TXPID5GHA0, ++ BRCMS_SROM_TXPID5GHA1, ++ BRCMS_SROM_TXPID5GHA2, ++ BRCMS_SROM_TXPID5GHA3, ++ BRCMS_SROM_TXPID5GLA0, ++ BRCMS_SROM_TXPID5GLA1, ++ BRCMS_SROM_TXPID5GLA2, ++ BRCMS_SROM_TXPID5GLA3, ++ /* ++ * per-path identifiers (see srom.c) ++ */ ++ BRCMS_SROM_ITT2GA0, ++ BRCMS_SROM_ITT2GA1, ++ BRCMS_SROM_ITT2GA2, ++ BRCMS_SROM_ITT2GA3, ++ BRCMS_SROM_ITT5GA0, ++ BRCMS_SROM_ITT5GA1, ++ BRCMS_SROM_ITT5GA2, ++ BRCMS_SROM_ITT5GA3, ++ BRCMS_SROM_MAXP2GA0, ++ BRCMS_SROM_MAXP2GA1, ++ BRCMS_SROM_MAXP2GA2, ++ BRCMS_SROM_MAXP2GA3, ++ BRCMS_SROM_MAXP5GA0, ++ BRCMS_SROM_MAXP5GA1, ++ BRCMS_SROM_MAXP5GA2, ++ BRCMS_SROM_MAXP5GA3, ++ BRCMS_SROM_MAXP5GHA0, ++ BRCMS_SROM_MAXP5GHA1, ++ BRCMS_SROM_MAXP5GHA2, ++ BRCMS_SROM_MAXP5GHA3, ++ BRCMS_SROM_MAXP5GLA0, ++ BRCMS_SROM_MAXP5GLA1, ++ BRCMS_SROM_MAXP5GLA2, ++ BRCMS_SROM_MAXP5GLA3, ++ BRCMS_SROM_PA2GW0A0, ++ BRCMS_SROM_PA2GW0A1, ++ BRCMS_SROM_PA2GW0A2, ++ BRCMS_SROM_PA2GW0A3, ++ BRCMS_SROM_PA2GW1A0, ++ BRCMS_SROM_PA2GW1A1, ++ BRCMS_SROM_PA2GW1A2, ++ BRCMS_SROM_PA2GW1A3, ++ BRCMS_SROM_PA2GW2A0, ++ BRCMS_SROM_PA2GW2A1, ++ BRCMS_SROM_PA2GW2A2, ++ BRCMS_SROM_PA2GW2A3, ++ BRCMS_SROM_PA2GW3A0, ++ BRCMS_SROM_PA2GW3A1, ++ BRCMS_SROM_PA2GW3A2, ++ BRCMS_SROM_PA2GW3A3, ++ BRCMS_SROM_PA5GHW0A0, ++ BRCMS_SROM_PA5GHW0A1, ++ BRCMS_SROM_PA5GHW0A2, ++ BRCMS_SROM_PA5GHW0A3, ++ BRCMS_SROM_PA5GHW1A0, ++ BRCMS_SROM_PA5GHW1A1, ++ BRCMS_SROM_PA5GHW1A2, ++ BRCMS_SROM_PA5GHW1A3, ++ BRCMS_SROM_PA5GHW2A0, ++ BRCMS_SROM_PA5GHW2A1, ++ BRCMS_SROM_PA5GHW2A2, ++ BRCMS_SROM_PA5GHW2A3, ++ BRCMS_SROM_PA5GHW3A0, ++ BRCMS_SROM_PA5GHW3A1, ++ BRCMS_SROM_PA5GHW3A2, ++ BRCMS_SROM_PA5GHW3A3, ++ BRCMS_SROM_PA5GLW0A0, ++ BRCMS_SROM_PA5GLW0A1, ++ BRCMS_SROM_PA5GLW0A2, ++ BRCMS_SROM_PA5GLW0A3, ++ BRCMS_SROM_PA5GLW1A0, ++ BRCMS_SROM_PA5GLW1A1, ++ BRCMS_SROM_PA5GLW1A2, ++ BRCMS_SROM_PA5GLW1A3, ++ BRCMS_SROM_PA5GLW2A0, ++ BRCMS_SROM_PA5GLW2A1, ++ BRCMS_SROM_PA5GLW2A2, ++ BRCMS_SROM_PA5GLW2A3, ++ BRCMS_SROM_PA5GLW3A0, ++ BRCMS_SROM_PA5GLW3A1, ++ BRCMS_SROM_PA5GLW3A2, ++ BRCMS_SROM_PA5GLW3A3, ++ BRCMS_SROM_PA5GW0A0, ++ BRCMS_SROM_PA5GW0A1, ++ BRCMS_SROM_PA5GW0A2, ++ BRCMS_SROM_PA5GW0A3, ++ BRCMS_SROM_PA5GW1A0, ++ BRCMS_SROM_PA5GW1A1, ++ BRCMS_SROM_PA5GW1A2, ++ BRCMS_SROM_PA5GW1A3, ++ BRCMS_SROM_PA5GW2A0, ++ BRCMS_SROM_PA5GW2A1, ++ BRCMS_SROM_PA5GW2A2, ++ BRCMS_SROM_PA5GW2A3, ++ BRCMS_SROM_PA5GW3A0, ++ BRCMS_SROM_PA5GW3A1, ++ BRCMS_SROM_PA5GW3A2, ++ BRCMS_SROM_PA5GW3A3, ++}; ++ ++#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */ ++#define D11_PHY_HDR_LEN 6 /* Phy header length - 6 bytes */ ++ ++/* phy types */ ++#define PHY_TYPE_A 0 /* Phy type A */ ++#define PHY_TYPE_G 2 /* Phy type G */ ++#define PHY_TYPE_N 4 /* Phy type N */ ++#define PHY_TYPE_LP 5 /* Phy type Low Power A/B/G */ ++#define PHY_TYPE_SSN 6 /* Phy type Single Stream N */ ++#define PHY_TYPE_LCN 8 /* Phy type Single Stream N */ ++#define PHY_TYPE_LCNXN 9 /* Phy type 2-stream N */ ++#define PHY_TYPE_HT 7 /* Phy type 3-Stream N */ ++ ++/* bw */ ++#define BRCMS_10_MHZ 10 /* 10Mhz nphy channel bandwidth */ ++#define BRCMS_20_MHZ 20 /* 20Mhz nphy channel bandwidth */ ++#define BRCMS_40_MHZ 40 /* 40Mhz nphy channel bandwidth */ ++ ++#define BRCMS_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */ ++#define BRCMS_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */ ++#define BRCMS_RSSI_VERY_LOW -80 /* Very low quality cutoffs */ ++#define BRCMS_RSSI_LOW -70 /* Low quality cutoffs */ ++#define BRCMS_RSSI_GOOD -68 /* Good quality cutoffs */ ++#define BRCMS_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */ ++#define BRCMS_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */ ++ ++/* a large TX Power as an init value to factor out of min() calculations, ++ * keep low enough to fit in an s8, units are .25 dBm ++ */ ++#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ ++ ++/* rate related definitions */ ++#define BRCMS_RATE_FLAG 0x80 /* Flag to indicate it is a basic rate */ ++#define BRCMS_RATE_MASK 0x7f /* Rate value mask w/o basic rate flag */ ++ ++/* legacy rx Antenna diversity for SISO rates */ ++#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */ ++#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */ ++#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */ ++#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */ ++#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */ ++/* default antdiv setting */ ++#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 ++ ++/* legacy rx Antenna diversity for SISO rates */ ++/* Tx on antenna 0, "legacy term Main" */ ++#define ANT_TX_FORCE_0 0 ++/* Tx on antenna 1, "legacy term Aux" */ ++#define ANT_TX_FORCE_1 1 ++/* Tx on phy's last good Rx antenna */ ++#define ANT_TX_LAST_RX 3 ++/* driver's default tx antenna setting */ ++#define ANT_TX_DEF 3 ++ ++/* Tx Chain values */ ++/* def bitmap of txchain */ ++#define TXCHAIN_DEF 0x1 ++/* default bitmap of tx chains for nphy */ ++#define TXCHAIN_DEF_NPHY 0x3 ++/* default bitmap of tx chains for nphy */ ++#define TXCHAIN_DEF_HTPHY 0x7 ++/* def bitmap of rxchain */ ++#define RXCHAIN_DEF 0x1 ++/* default bitmap of rx chains for nphy */ ++#define RXCHAIN_DEF_NPHY 0x3 ++/* default bitmap of rx chains for nphy */ ++#define RXCHAIN_DEF_HTPHY 0x7 ++/* no antenna switch */ ++#define ANTSWITCH_NONE 0 ++/* antenna switch on 4321CB2, 2of3 */ ++#define ANTSWITCH_TYPE_1 1 ++/* antenna switch on 4321MPCI, 2of3 */ ++#define ANTSWITCH_TYPE_2 2 ++/* antenna switch on 4322, 2of3 */ ++#define ANTSWITCH_TYPE_3 3 ++ ++#define RXBUFSZ PKTBUFSZ ++ ++#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ ++ ++struct brcm_rateset { ++ /* # rates in this set */ ++ u32 count; ++ /* rates in 500kbps units w/hi bit set if basic */ ++ u8 rates[WL_NUMRATES]; ++}; ++ ++struct brcms_c_rateset { ++ uint count; /* number of rates in rates[] */ ++ /* rates in 500kbps units w/hi bit set if basic */ ++ u8 rates[BRCMS_NUMRATES]; ++ u8 htphy_membership; /* HT PHY Membership */ ++ u8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ ++}; ++ ++/* All the HT-specific default advertised capabilities (including AMPDU) ++ * should be grouped here at one place ++ */ ++#define AMPDU_DEF_MPDU_DENSITY 6 /* default mpdu density (110 ==> 4us) */ ++ ++/* wlc internal bss_info */ ++struct brcms_bss_info { ++ u8 BSSID[ETH_ALEN]; /* network BSSID */ ++ u16 flags; /* flags for internal attributes */ ++ u8 SSID_len; /* the length of SSID */ ++ u8 SSID[32]; /* SSID string */ ++ s16 RSSI; /* receive signal strength (in dBm) */ ++ s16 SNR; /* receive signal SNR in dB */ ++ u16 beacon_period; /* units are Kusec */ ++ u16 chanspec; /* Channel num, bw, ctrl_sb and band */ ++ struct brcms_c_rateset rateset; /* supported rates */ ++}; ++ ++#define MAC80211_PROMISC_BCNS (1 << 0) ++#define MAC80211_SCAN (1 << 1) ++ ++/* ++ * Public portion of common driver state structure. ++ * The wlc handle points at this. ++ */ ++struct brcms_pub { ++ struct brcms_c_info *wlc; ++ struct ieee80211_hw *ieee_hw; ++ struct scb_ampdu *global_ampdu; ++ uint mac80211_state; ++ uint unit; /* device instance number */ ++ uint corerev; /* core revision */ ++ struct si_pub *sih; /* SI handle (cookie for siutils calls) */ ++ bool up; /* interface up and running */ ++ bool hw_off; /* HW is off */ ++ bool hw_up; /* one time hw up/down */ ++ bool _piomode; /* true if pio mode */ ++ uint _nbands; /* # bands supported */ ++ uint now; /* # elapsed seconds */ ++ ++ bool promisc; /* promiscuous destination address */ ++ bool delayed_down; /* down delayed */ ++ bool associated; /* true:part of [I]BSS, false: not */ ++ /* (union of stas_associated, aps_associated) */ ++ bool _ampdu; /* ampdu enabled or not */ ++ u8 _n_enab; /* bitmap of 11N + HT support */ ++ ++ u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */ ++ ++ int bcmerror; /* last bcm error */ ++ ++ u32 radio_disabled; /* bit vector for radio disabled reasons */ ++ ++ u16 boardrev; /* version # of particular board */ ++ u8 sromrev; /* version # of the srom */ ++ char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */ ++ u32 boardflags; /* Board specific flags from srom */ ++ u32 boardflags2; /* More board flags if sromrev >= 4 */ ++ bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */ ++ ++ struct wl_cnt *_cnt; /* low-level counters in driver */ ++}; ++ ++enum wlc_par_id { ++ IOV_MPC = 1, ++ IOV_RTSTHRESH, ++ IOV_QTXPOWER, ++ IOV_BCN_LI_BCN /* Beacon listen interval in # of beacons */ ++}; ++ ++/*********************************************** ++ * Feature-related macros to optimize out code * ++ * ********************************************* ++ */ ++ ++#define ENAB_1x1 0x01 ++#define ENAB_2x2 0x02 ++#define ENAB_3x3 0x04 ++#define ENAB_4x4 0x08 ++#define SUPPORT_11N (ENAB_1x1|ENAB_2x2) ++#define SUPPORT_HT (ENAB_1x1|ENAB_2x2|ENAB_3x3) ++ ++/* WL11N Support */ ++#define AMPDU_AGG_HOST 1 ++ ++/* pri is priority encoded in the packet. This maps the Packet priority to ++ * enqueue precedence as defined in wlc_prec_map ++ */ ++extern const u8 wlc_prio2prec_map[]; ++#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7] ++ ++#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */ ++ ++/* Mask to describe all precedence levels */ ++#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT) ++ ++/* ++ * This maps priority to one precedence higher - Used by PS-Poll response ++ * packets to simulate enqueue-at-head operation, but still maintain the ++ * order on the queue ++ */ ++#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\ ++ BRCMS_PREC_COUNT - 1) ++ ++/* Define a bitmap of precedences comprised by each AC */ ++#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \ ++ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE))) ++#define BRCMS_PREC_BMP_AC_BK (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \ ++ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE))) ++#define BRCMS_PREC_BMP_AC_VI (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \ ++ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI))) ++#define BRCMS_PREC_BMP_AC_VO (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \ ++ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \ ++ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC))) ++ ++/* network protection config */ ++#define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */ ++#define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */ ++#define BRCMS_PROT_G_USER 3 /* gmode specified by user */ ++#define BRCMS_PROT_OVERLAP 4 /* overlap */ ++#define BRCMS_PROT_N_USER 10 /* nmode specified by user */ ++#define BRCMS_PROT_N_CFG 11 /* n protection */ ++#define BRCMS_PROT_N_CFG_OVR 12 /* n protection override */ ++#define BRCMS_PROT_N_NONGF 13 /* non-GF protection */ ++#define BRCMS_PROT_N_NONGF_OVR 14 /* non-GF protection override */ ++#define BRCMS_PROT_N_PAM_OVR 15 /* n preamble override */ ++#define BRCMS_PROT_N_OBSS 16 /* non-HT OBSS present */ ++ ++/* ++ * 54g modes (basic bits may still be overridden) ++ * ++ * GMODE_LEGACY_B ++ * Rateset: 1b, 2b, 5.5, 11 ++ * Preamble: Long ++ * Shortslot: Off ++ * GMODE_AUTO ++ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: Auto ++ * GMODE_ONLY ++ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 ++ * Extended Rateset: 6b, 9, 12b, 48 ++ * Preamble: Short required ++ * Shortslot: Auto ++ * GMODE_B_DEFERRED ++ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: On ++ * GMODE_PERFORMANCE ++ * Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 ++ * Preamble: Short required ++ * Shortslot: On and required ++ * GMODE_LRS ++ * Rateset: 1b, 2b, 5.5b, 11b ++ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 ++ * Preamble: Long ++ * Shortslot: Auto ++ */ ++#define GMODE_LEGACY_B 0 ++#define GMODE_AUTO 1 ++#define GMODE_ONLY 2 ++#define GMODE_B_DEFERRED 3 ++#define GMODE_PERFORMANCE 4 ++#define GMODE_LRS 5 ++#define GMODE_MAX 6 ++ ++/* MCS values greater than this enable multiple streams */ ++#define HIGHEST_SINGLE_STREAM_MCS 7 ++ ++#define MAXBANDS 2 /* Maximum #of bands */ ++ ++/* max number of antenna configurations */ ++#define ANT_SELCFG_MAX 4 ++ ++struct brcms_antselcfg { ++ u8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ ++ u8 num_antcfg; /* number of available antenna configurations */ ++}; ++ ++/* common functions for every port */ ++extern struct brcms_c_info * ++brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, ++ bool piomode, void __iomem *regsva, struct pci_dev *btparam, ++ uint *perr); ++extern uint brcms_c_detach(struct brcms_c_info *wlc); ++extern int brcms_c_up(struct brcms_c_info *wlc); ++extern uint brcms_c_down(struct brcms_c_info *wlc); ++ ++extern bool brcms_c_chipmatch(u16 vendor, u16 device); ++extern void brcms_c_init(struct brcms_c_info *wlc); ++extern void brcms_c_reset(struct brcms_c_info *wlc); ++ ++extern void brcms_c_intrson(struct brcms_c_info *wlc); ++extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc); ++extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); ++extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); ++extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc); ++extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); ++extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, ++ struct sk_buff *sdu, ++ struct ieee80211_hw *hw); ++extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); ++extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, ++ int val); ++extern int brcms_c_get_header_len(void); ++extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc, ++ int match_reg_offset, ++ const u8 *addr); ++extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, ++ const struct ieee80211_tx_queue_params *arg, ++ bool suspend); ++extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc); ++extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc, ++ struct ieee80211_sta *sta, u16 tid); ++extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, ++ u8 ba_wsize, uint max_rx_ampdu_bytes); ++extern char *getvar(struct si_pub *sih, enum brcms_srom_id id); ++extern int getintvar(struct si_pub *sih, enum brcms_srom_id id); ++extern int brcms_c_module_register(struct brcms_pub *pub, ++ const char *name, struct brcms_info *hdl, ++ int (*down_fn)(void *handle)); ++extern int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, ++ struct brcms_info *hdl); ++extern void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc); ++extern void brcms_c_enable_mac(struct brcms_c_info *wlc); ++extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); ++extern void brcms_c_scan_start(struct brcms_c_info *wlc); ++extern void brcms_c_scan_stop(struct brcms_c_info *wlc); ++extern int brcms_c_get_curband(struct brcms_c_info *wlc); ++extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, ++ bool drop); ++extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); ++extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); ++extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, ++ struct brcm_rateset *currs); ++extern int brcms_c_set_rateset(struct brcms_c_info *wlc, ++ struct brcm_rateset *rs); ++extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period); ++extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx); ++extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, ++ s8 sslot_override); ++extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, ++ u8 interval); ++extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); ++extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); ++extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc); ++extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); ++ ++#endif /* _BRCM_PUB_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.c.orig 2011-11-09 13:46:58.284800145 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.c 2011-11-09 13:47:17.042565640 -0500 +@@ -0,0 +1,514 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++ ++#include "d11.h" ++#include "pub.h" ++#include "rate.h" ++ ++/* ++ * Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate ++ * value ++ */ ++const u8 rate_info[BRCM_MAXRATE + 1] = { ++ /* 0 1 2 3 4 5 6 7 8 9 */ ++/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, ++/* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, ++/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, ++/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, ++/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c ++}; ++ ++/* rates are in units of Kbps */ ++const struct brcms_mcs_info mcs_table[MCS_TABLE_SIZE] = { ++ /* MCS 0: SS 1, MOD: BPSK, CR 1/2 */ ++ {6500, 13500, CEIL(6500 * 10, 9), CEIL(13500 * 10, 9), 0x00, ++ BRCM_RATE_6M}, ++ /* MCS 1: SS 1, MOD: QPSK, CR 1/2 */ ++ {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x08, ++ BRCM_RATE_12M}, ++ /* MCS 2: SS 1, MOD: QPSK, CR 3/4 */ ++ {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x0A, ++ BRCM_RATE_18M}, ++ /* MCS 3: SS 1, MOD: 16QAM, CR 1/2 */ ++ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x10, ++ BRCM_RATE_24M}, ++ /* MCS 4: SS 1, MOD: 16QAM, CR 3/4 */ ++ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x12, ++ BRCM_RATE_36M}, ++ /* MCS 5: SS 1, MOD: 64QAM, CR 2/3 */ ++ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x19, ++ BRCM_RATE_48M}, ++ /* MCS 6: SS 1, MOD: 64QAM, CR 3/4 */ ++ {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x1A, ++ BRCM_RATE_54M}, ++ /* MCS 7: SS 1, MOD: 64QAM, CR 5/6 */ ++ {65000, 135000, CEIL(65000 * 10, 9), CEIL(135000 * 10, 9), 0x1C, ++ BRCM_RATE_54M}, ++ /* MCS 8: SS 2, MOD: BPSK, CR 1/2 */ ++ {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x40, ++ BRCM_RATE_6M}, ++ /* MCS 9: SS 2, MOD: QPSK, CR 1/2 */ ++ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x48, ++ BRCM_RATE_12M}, ++ /* MCS 10: SS 2, MOD: QPSK, CR 3/4 */ ++ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x4A, ++ BRCM_RATE_18M}, ++ /* MCS 11: SS 2, MOD: 16QAM, CR 1/2 */ ++ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x50, ++ BRCM_RATE_24M}, ++ /* MCS 12: SS 2, MOD: 16QAM, CR 3/4 */ ++ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x52, ++ BRCM_RATE_36M}, ++ /* MCS 13: SS 2, MOD: 64QAM, CR 2/3 */ ++ {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0x59, ++ BRCM_RATE_48M}, ++ /* MCS 14: SS 2, MOD: 64QAM, CR 3/4 */ ++ {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x5A, ++ BRCM_RATE_54M}, ++ /* MCS 15: SS 2, MOD: 64QAM, CR 5/6 */ ++ {130000, 270000, CEIL(130000 * 10, 9), CEIL(270000 * 10, 9), 0x5C, ++ BRCM_RATE_54M}, ++ /* MCS 16: SS 3, MOD: BPSK, CR 1/2 */ ++ {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x80, ++ BRCM_RATE_6M}, ++ /* MCS 17: SS 3, MOD: QPSK, CR 1/2 */ ++ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x88, ++ BRCM_RATE_12M}, ++ /* MCS 18: SS 3, MOD: QPSK, CR 3/4 */ ++ {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x8A, ++ BRCM_RATE_18M}, ++ /* MCS 19: SS 3, MOD: 16QAM, CR 1/2 */ ++ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x90, ++ BRCM_RATE_24M}, ++ /* MCS 20: SS 3, MOD: 16QAM, CR 3/4 */ ++ {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x92, ++ BRCM_RATE_36M}, ++ /* MCS 21: SS 3, MOD: 64QAM, CR 2/3 */ ++ {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0x99, ++ BRCM_RATE_48M}, ++ /* MCS 22: SS 3, MOD: 64QAM, CR 3/4 */ ++ {175500, 364500, CEIL(175500 * 10, 9), CEIL(364500 * 10, 9), 0x9A, ++ BRCM_RATE_54M}, ++ /* MCS 23: SS 3, MOD: 64QAM, CR 5/6 */ ++ {195000, 405000, CEIL(195000 * 10, 9), CEIL(405000 * 10, 9), 0x9B, ++ BRCM_RATE_54M}, ++ /* MCS 24: SS 4, MOD: BPSK, CR 1/2 */ ++ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0xC0, ++ BRCM_RATE_6M}, ++ /* MCS 25: SS 4, MOD: QPSK, CR 1/2 */ ++ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0xC8, ++ BRCM_RATE_12M}, ++ /* MCS 26: SS 4, MOD: QPSK, CR 3/4 */ ++ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0xCA, ++ BRCM_RATE_18M}, ++ /* MCS 27: SS 4, MOD: 16QAM, CR 1/2 */ ++ {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0xD0, ++ BRCM_RATE_24M}, ++ /* MCS 28: SS 4, MOD: 16QAM, CR 3/4 */ ++ {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0xD2, ++ BRCM_RATE_36M}, ++ /* MCS 29: SS 4, MOD: 64QAM, CR 2/3 */ ++ {208000, 432000, CEIL(208000 * 10, 9), CEIL(432000 * 10, 9), 0xD9, ++ BRCM_RATE_48M}, ++ /* MCS 30: SS 4, MOD: 64QAM, CR 3/4 */ ++ {234000, 486000, CEIL(234000 * 10, 9), CEIL(486000 * 10, 9), 0xDA, ++ BRCM_RATE_54M}, ++ /* MCS 31: SS 4, MOD: 64QAM, CR 5/6 */ ++ {260000, 540000, CEIL(260000 * 10, 9), CEIL(540000 * 10, 9), 0xDB, ++ BRCM_RATE_54M}, ++ /* MCS 32: SS 1, MOD: BPSK, CR 1/2 */ ++ {0, 6000, 0, CEIL(6000 * 10, 9), 0x00, BRCM_RATE_6M}, ++}; ++ ++/* ++ * phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams ++ * Number of spatial streams: always 1 other fields: refer to table 78 of ++ * section 17.3.2.2 of the original .11a standard ++ */ ++struct legacy_phycfg { ++ u32 rate_ofdm; /* ofdm mac rate */ ++ /* phy ctl byte 3, code rate, modulation type, # of streams */ ++ u8 tx_phy_ctl3; ++}; ++ ++/* Number of legacy_rate_cfg entries in the table */ ++#define LEGACY_PHYCFG_TABLE_SIZE 12 ++ ++/* ++ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate ++ * Eventually MIMOPHY would also be converted to this format ++ * 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps ++ */ ++static const struct ++legacy_phycfg legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = { ++ {BRCM_RATE_1M, 0x00}, /* CCK 1Mbps, data rate 0 */ ++ {BRCM_RATE_2M, 0x08}, /* CCK 2Mbps, data rate 1 */ ++ {BRCM_RATE_5M5, 0x10}, /* CCK 5.5Mbps, data rate 2 */ ++ {BRCM_RATE_11M, 0x18}, /* CCK 11Mbps, data rate 3 */ ++ /* OFDM 6Mbps, code rate 1/2, BPSK, 1 spatial stream */ ++ {BRCM_RATE_6M, 0x00}, ++ /* OFDM 9Mbps, code rate 3/4, BPSK, 1 spatial stream */ ++ {BRCM_RATE_9M, 0x02}, ++ /* OFDM 12Mbps, code rate 1/2, QPSK, 1 spatial stream */ ++ {BRCM_RATE_12M, 0x08}, ++ /* OFDM 18Mbps, code rate 3/4, QPSK, 1 spatial stream */ ++ {BRCM_RATE_18M, 0x0A}, ++ /* OFDM 24Mbps, code rate 1/2, 16-QAM, 1 spatial stream */ ++ {BRCM_RATE_24M, 0x10}, ++ /* OFDM 36Mbps, code rate 3/4, 16-QAM, 1 spatial stream */ ++ {BRCM_RATE_36M, 0x12}, ++ /* OFDM 48Mbps, code rate 2/3, 64-QAM, 1 spatial stream */ ++ {BRCM_RATE_48M, 0x19}, ++ /* OFDM 54Mbps, code rate 3/4, 64-QAM, 1 spatial stream */ ++ {BRCM_RATE_54M, 0x1A}, ++}; ++ ++/* Hardware rates (also encodes default basic rates) */ ++ ++const struct brcms_c_rateset cck_ofdm_mimo_rates = { ++ 12, ++ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, */ ++ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, ++ /* 54 Mbps */ ++ 0x6c}, ++ 0x00, ++ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++const struct brcms_c_rateset ofdm_mimo_rates = { ++ 8, ++ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ ++ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, ++ 0x00, ++ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* Default ratesets that include MCS32 for 40BW channels */ ++static const struct brcms_c_rateset cck_ofdm_40bw_mimo_rates = { ++ 12, ++ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48 */ ++ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, ++ /* 54 Mbps */ ++ 0x6c}, ++ 0x00, ++ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++static const struct brcms_c_rateset ofdm_40bw_mimo_rates = { ++ 8, ++ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ ++ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, ++ 0x00, ++ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++const struct brcms_c_rateset cck_ofdm_rates = { ++ 12, ++ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48,*/ ++ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, ++ /*54 Mbps */ ++ 0x6c}, ++ 0x00, ++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++const struct brcms_c_rateset gphy_legacy_rates = { ++ 4, ++ /* 1b, 2b, 5.5b, 11b Mbps */ ++ { 0x82, 0x84, 0x8b, 0x96}, ++ 0x00, ++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++const struct brcms_c_rateset ofdm_rates = { ++ 8, ++ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ ++ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, ++ 0x00, ++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++const struct brcms_c_rateset cck_rates = { ++ 4, ++ /* 1b, 2b, 5.5, 11 Mbps */ ++ { 0x82, 0x84, 0x0b, 0x16}, ++ 0x00, ++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00} ++}; ++ ++/* check if rateset is valid. ++ * if check_brate is true, rateset without a basic rate is considered NOT valid. ++ */ ++static bool brcms_c_rateset_valid(struct brcms_c_rateset *rs, bool check_brate) ++{ ++ uint idx; ++ ++ if (!rs->count) ++ return false; ++ ++ if (!check_brate) ++ return true; ++ ++ /* error if no basic rates */ ++ for (idx = 0; idx < rs->count; idx++) { ++ if (rs->rates[idx] & BRCMS_RATE_FLAG) ++ return true; ++ } ++ return false; ++} ++ ++void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams) ++{ ++ int i; ++ for (i = txstreams; i < MAX_STREAMS_SUPPORTED; i++) ++ rs->mcs[i] = 0; ++} ++ ++/* ++ * filter based on hardware rateset, and sort filtered rateset with basic ++ * bit(s) preserved, and check if resulting rateset is valid. ++*/ ++bool ++brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, ++ const struct brcms_c_rateset *hw_rs, ++ bool check_brate, u8 txstreams) ++{ ++ u8 rateset[BRCM_MAXRATE + 1]; ++ u8 r; ++ uint count; ++ uint i; ++ ++ memset(rateset, 0, sizeof(rateset)); ++ count = rs->count; ++ ++ for (i = 0; i < count; i++) { ++ /* mask off "basic rate" bit, BRCMS_RATE_FLAG */ ++ r = (int)rs->rates[i] & BRCMS_RATE_MASK; ++ if ((r > BRCM_MAXRATE) || (rate_info[r] == 0)) ++ continue; ++ rateset[r] = rs->rates[i]; /* preserve basic bit! */ ++ } ++ ++ /* fill out the rates in order, looking at only supported rates */ ++ count = 0; ++ for (i = 0; i < hw_rs->count; i++) { ++ r = hw_rs->rates[i] & BRCMS_RATE_MASK; ++ if (rateset[r]) ++ rs->rates[count++] = rateset[r]; ++ } ++ ++ rs->count = count; ++ ++ /* only set the mcs rate bit if the equivalent hw mcs bit is set */ ++ for (i = 0; i < MCSSET_LEN; i++) ++ rs->mcs[i] = (rs->mcs[i] & hw_rs->mcs[i]); ++ ++ if (brcms_c_rateset_valid(rs, check_brate)) ++ return true; ++ else ++ return false; ++} ++ ++/* calculate the rate of a rx'd frame and return it as a ratespec */ ++u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp) ++{ ++ int phy_type; ++ u32 rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT; ++ ++ phy_type = ++ ((rxh->RxChan & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT); ++ ++ if ((phy_type == PHY_TYPE_N) || (phy_type == PHY_TYPE_SSN) || ++ (phy_type == PHY_TYPE_LCN) || (phy_type == PHY_TYPE_HT)) { ++ switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) { ++ case PRXS0_CCK: ++ rspec = ++ cck_phy2mac_rate( ++ ((struct cck_phy_hdr *) plcp)->signal); ++ break; ++ case PRXS0_OFDM: ++ rspec = ++ ofdm_phy2mac_rate( ++ ((struct ofdm_phy_hdr *) plcp)->rlpt[0]); ++ break; ++ case PRXS0_PREN: ++ rspec = (plcp[0] & MIMO_PLCP_MCS_MASK) | RSPEC_MIMORATE; ++ if (plcp[0] & MIMO_PLCP_40MHZ) { ++ /* indicate rspec is for 40 MHz mode */ ++ rspec &= ~RSPEC_BW_MASK; ++ rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); ++ } ++ break; ++ case PRXS0_STDN: ++ /* fallthru */ ++ default: ++ /* not supported, error condition */ ++ break; ++ } ++ if (plcp3_issgi(plcp[3])) ++ rspec |= RSPEC_SHORT_GI; ++ } else ++ if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM)) ++ rspec = ofdm_phy2mac_rate( ++ ((struct ofdm_phy_hdr *) plcp)->rlpt[0]); ++ else ++ rspec = cck_phy2mac_rate( ++ ((struct cck_phy_hdr *) plcp)->signal); ++ ++ return rspec; ++} ++ ++/* copy rateset src to dst as-is (no masking or sorting) */ ++void brcms_c_rateset_copy(const struct brcms_c_rateset *src, ++ struct brcms_c_rateset *dst) ++{ ++ memcpy(dst, src, sizeof(struct brcms_c_rateset)); ++} ++ ++/* ++ * Copy and selectively filter one rateset to another. ++ * 'basic_only' means only copy basic rates. ++ * 'rates' indicates cck (11b) and ofdm rates combinations. ++ * - 0: cck and ofdm ++ * - 1: cck only ++ * - 2: ofdm only ++ * 'xmask' is the copy mask (typically 0x7f or 0xff). ++ */ ++void ++brcms_c_rateset_filter(struct brcms_c_rateset *src, struct brcms_c_rateset *dst, ++ bool basic_only, u8 rates, uint xmask, bool mcsallow) ++{ ++ uint i; ++ uint r; ++ uint count; ++ ++ count = 0; ++ for (i = 0; i < src->count; i++) { ++ r = src->rates[i]; ++ if (basic_only && !(r & BRCMS_RATE_FLAG)) ++ continue; ++ if (rates == BRCMS_RATES_CCK && ++ is_ofdm_rate((r & BRCMS_RATE_MASK))) ++ continue; ++ if (rates == BRCMS_RATES_OFDM && ++ is_cck_rate((r & BRCMS_RATE_MASK))) ++ continue; ++ dst->rates[count++] = r & xmask; ++ } ++ dst->count = count; ++ dst->htphy_membership = src->htphy_membership; ++ ++ if (mcsallow && rates != BRCMS_RATES_CCK) ++ memcpy(&dst->mcs[0], &src->mcs[0], MCSSET_LEN); ++ else ++ brcms_c_rateset_mcs_clear(dst); ++} ++ ++/* select rateset for a given phy_type and bandtype and filter it, sort it ++ * and fill rs_tgt with result ++ */ ++void ++brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, ++ const struct brcms_c_rateset *rs_hw, ++ uint phy_type, int bandtype, bool cck_only, ++ uint rate_mask, bool mcsallow, u8 bw, u8 txstreams) ++{ ++ const struct brcms_c_rateset *rs_dflt; ++ struct brcms_c_rateset rs_sel; ++ if ((PHYTYPE_IS(phy_type, PHY_TYPE_HT)) || ++ (PHYTYPE_IS(phy_type, PHY_TYPE_N)) || ++ (PHYTYPE_IS(phy_type, PHY_TYPE_LCN)) || ++ (PHYTYPE_IS(phy_type, PHY_TYPE_SSN))) { ++ if (bandtype == BRCM_BAND_5G) ++ rs_dflt = (bw == BRCMS_20_MHZ ? ++ &ofdm_mimo_rates : &ofdm_40bw_mimo_rates); ++ else ++ rs_dflt = (bw == BRCMS_20_MHZ ? ++ &cck_ofdm_mimo_rates : ++ &cck_ofdm_40bw_mimo_rates); ++ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_LP)) { ++ rs_dflt = (bandtype == BRCM_BAND_5G) ? ++ &ofdm_rates : &cck_ofdm_rates; ++ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_A)) { ++ rs_dflt = &ofdm_rates; ++ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_G)) { ++ rs_dflt = &cck_ofdm_rates; ++ } else { ++ /* should not happen, error condition */ ++ rs_dflt = &cck_rates; /* force cck */ ++ } ++ ++ /* if hw rateset is not supplied, assign selected rateset to it */ ++ if (!rs_hw) ++ rs_hw = rs_dflt; ++ ++ brcms_c_rateset_copy(rs_dflt, &rs_sel); ++ brcms_c_rateset_mcs_upd(&rs_sel, txstreams); ++ brcms_c_rateset_filter(&rs_sel, rs_tgt, false, ++ cck_only ? BRCMS_RATES_CCK : BRCMS_RATES_CCK_OFDM, ++ rate_mask, mcsallow); ++ brcms_c_rate_hwrs_filter_sort_validate(rs_tgt, rs_hw, false, ++ mcsallow ? txstreams : 1); ++} ++ ++s16 brcms_c_rate_legacy_phyctl(uint rate) ++{ ++ uint i; ++ for (i = 0; i < LEGACY_PHYCFG_TABLE_SIZE; i++) ++ if (rate == legacy_phycfg_table[i].rate_ofdm) ++ return legacy_phycfg_table[i].tx_phy_ctl3; ++ ++ return -1; ++} ++ ++void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset) ++{ ++ uint i; ++ for (i = 0; i < MCSSET_LEN; i++) ++ rateset->mcs[i] = 0; ++} ++ ++void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, u8 txstreams) ++{ ++ memcpy(&rateset->mcs[0], &cck_ofdm_mimo_rates.mcs[0], MCSSET_LEN); ++ brcms_c_rateset_mcs_upd(rateset, txstreams); ++} ++ ++/* Based on bandwidth passed, allow/disallow MCS 32 in the rateset */ ++void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, u8 bw) ++{ ++ if (bw == BRCMS_40_MHZ) ++ setbit(rateset->mcs, 32); ++ else ++ clrbit(rateset->mcs, 32); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.h.orig 2011-11-09 13:46:58.284800145 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/rate.h 2011-11-09 13:47:17.043565628 -0500 +@@ -0,0 +1,250 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_RATE_H_ ++#define _BRCM_RATE_H_ ++ ++#include "types.h" ++#include "d11.h" ++ ++extern const u8 rate_info[]; ++extern const struct brcms_c_rateset cck_ofdm_mimo_rates; ++extern const struct brcms_c_rateset ofdm_mimo_rates; ++extern const struct brcms_c_rateset cck_ofdm_rates; ++extern const struct brcms_c_rateset ofdm_rates; ++extern const struct brcms_c_rateset cck_rates; ++extern const struct brcms_c_rateset gphy_legacy_rates; ++extern const struct brcms_c_rateset rate_limit_1_2; ++ ++struct brcms_mcs_info { ++ /* phy rate in kbps [20Mhz] */ ++ u32 phy_rate_20; ++ /* phy rate in kbps [40Mhz] */ ++ u32 phy_rate_40; ++ /* phy rate in kbps [20Mhz] with SGI */ ++ u32 phy_rate_20_sgi; ++ /* phy rate in kbps [40Mhz] with SGI */ ++ u32 phy_rate_40_sgi; ++ /* phy ctl byte 3, code rate, modulation type, # of streams */ ++ u8 tx_phy_ctl3; ++ /* matching legacy ofdm rate in 500bkps */ ++ u8 leg_ofdm; ++}; ++ ++#define BRCMS_MAXMCS 32 /* max valid mcs index */ ++#define MCS_TABLE_SIZE 33 /* Number of mcs entries in the table */ ++extern const struct brcms_mcs_info mcs_table[]; ++ ++#define MCS_TXS_MASK 0xc0 /* num tx streams - 1 bit mask */ ++#define MCS_TXS_SHIFT 6 /* num tx streams - 1 bit shift */ ++ ++/* returns num tx streams - 1 */ ++static inline u8 mcs_2_txstreams(u8 mcs) ++{ ++ return (mcs_table[mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT; ++} ++ ++static inline uint mcs_2_rate(u8 mcs, bool is40, bool sgi) ++{ ++ if (sgi) { ++ if (is40) ++ return mcs_table[mcs].phy_rate_40_sgi; ++ return mcs_table[mcs].phy_rate_20_sgi; ++ } ++ if (is40) ++ return mcs_table[mcs].phy_rate_40; ++ ++ return mcs_table[mcs].phy_rate_20; ++} ++ ++/* Macro to use the rate_info table */ ++#define BRCMS_RATE_MASK_FULL 0xff /* Rate value mask with basic rate flag */ ++ ++/* ++ * rate spec : holds rate and mode specific information required to generate a ++ * tx frame. Legacy CCK and OFDM information is held in the same manner as was ++ * done in the past (in the lower byte) the upper 3 bytes primarily hold MIMO ++ * specific information ++ */ ++ ++/* rate spec bit fields */ ++ ++/* Either 500Kbps units or MIMO MCS idx */ ++#define RSPEC_RATE_MASK 0x0000007F ++/* mimo MCS is stored in RSPEC_RATE_MASK */ ++#define RSPEC_MIMORATE 0x08000000 ++/* mimo bw mask */ ++#define RSPEC_BW_MASK 0x00000700 ++/* mimo bw shift */ ++#define RSPEC_BW_SHIFT 8 ++/* mimo Space/Time/Frequency mode mask */ ++#define RSPEC_STF_MASK 0x00003800 ++/* mimo Space/Time/Frequency mode shift */ ++#define RSPEC_STF_SHIFT 11 ++/* mimo coding type mask */ ++#define RSPEC_CT_MASK 0x0000C000 ++/* mimo coding type shift */ ++#define RSPEC_CT_SHIFT 14 ++/* mimo num STC streams per PLCP defn. */ ++#define RSPEC_STC_MASK 0x00300000 ++/* mimo num STC streams per PLCP defn. */ ++#define RSPEC_STC_SHIFT 20 ++/* mimo bit indicates adv coding in use */ ++#define RSPEC_LDPC_CODING 0x00400000 ++/* mimo bit indicates short GI in use */ ++#define RSPEC_SHORT_GI 0x00800000 ++/* bit indicates override both rate & mode */ ++#define RSPEC_OVERRIDE 0x80000000 ++/* bit indicates override rate only */ ++#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000 ++ ++static inline bool rspec_active(u32 rspec) ++{ ++ return rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE); ++} ++ ++static inline u8 rspec_phytxbyte2(u32 rspec) ++{ ++ return (rspec & 0xff00) >> 8; ++} ++ ++static inline u32 rspec_get_bw(u32 rspec) ++{ ++ return (rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT; ++} ++ ++static inline bool rspec_issgi(u32 rspec) ++{ ++ return (rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI; ++} ++ ++static inline bool rspec_is40mhz(u32 rspec) ++{ ++ u32 bw = rspec_get_bw(rspec); ++ ++ return bw == PHY_TXC1_BW_40MHZ || bw == PHY_TXC1_BW_40MHZ_DUP; ++} ++ ++static inline uint rspec2rate(u32 rspec) ++{ ++ if (rspec & RSPEC_MIMORATE) ++ return mcs_2_rate(rspec & RSPEC_RATE_MASK, rspec_is40mhz(rspec), ++ rspec_issgi(rspec)); ++ return rspec & RSPEC_RATE_MASK; ++} ++ ++static inline u8 rspec_mimoplcp3(u32 rspec) ++{ ++ return (rspec & 0xf00000) >> 16; ++} ++ ++static inline bool plcp3_issgi(u8 plcp) ++{ ++ return (plcp & (RSPEC_SHORT_GI >> 16)) != 0; ++} ++ ++static inline uint rspec_stc(u32 rspec) ++{ ++ return (rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT; ++} ++ ++static inline uint rspec_stf(u32 rspec) ++{ ++ return (rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT; ++} ++ ++static inline bool is_mcs_rate(u32 ratespec) ++{ ++ return (ratespec & RSPEC_MIMORATE) != 0; ++} ++ ++static inline bool is_ofdm_rate(u32 ratespec) ++{ ++ return !is_mcs_rate(ratespec) && ++ (rate_info[ratespec & RSPEC_RATE_MASK] & BRCMS_RATE_FLAG); ++} ++ ++static inline bool is_cck_rate(u32 ratespec) ++{ ++ u32 rate = (ratespec & BRCMS_RATE_MASK); ++ ++ return !is_mcs_rate(ratespec) && ( ++ rate == BRCM_RATE_1M || rate == BRCM_RATE_2M || ++ rate == BRCM_RATE_5M5 || rate == BRCM_RATE_11M); ++} ++ ++static inline bool is_single_stream(u8 mcs) ++{ ++ return mcs <= HIGHEST_SINGLE_STREAM_MCS || mcs == 32; ++} ++ ++static inline u8 cck_rspec(u8 cck) ++{ ++ return cck & RSPEC_RATE_MASK; ++} ++ ++/* Convert encoded rate value in plcp header to numerical rates in 500 KHz ++ * increments */ ++extern const u8 ofdm_rate_lookup[]; ++ ++static inline u8 ofdm_phy2mac_rate(u8 rlpt) ++{ ++ return ofdm_rate_lookup[rlpt & 0x7]; ++} ++ ++static inline u8 cck_phy2mac_rate(u8 signal) ++{ ++ return signal/5; ++} ++ ++/* Rates specified in brcms_c_rateset_filter() */ ++#define BRCMS_RATES_CCK_OFDM 0 ++#define BRCMS_RATES_CCK 1 ++#define BRCMS_RATES_OFDM 2 ++ ++/* sanitize, and sort a rateset with the basic bit(s) preserved, validate ++ * rateset */ ++extern bool ++brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, ++ const struct brcms_c_rateset *hw_rs, ++ bool check_brate, u8 txstreams); ++/* copy rateset src to dst as-is (no masking or sorting) */ ++extern void brcms_c_rateset_copy(const struct brcms_c_rateset *src, ++ struct brcms_c_rateset *dst); ++ ++/* would be nice to have these documented ... */ ++extern u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp); ++ ++extern void brcms_c_rateset_filter(struct brcms_c_rateset *src, ++ struct brcms_c_rateset *dst, bool basic_only, u8 rates, uint xmask, ++ bool mcsallow); ++ ++extern void ++brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, ++ const struct brcms_c_rateset *rs_hw, uint phy_type, ++ int bandtype, bool cck_only, uint rate_mask, ++ bool mcsallow, u8 bw, u8 txstreams); ++ ++extern s16 brcms_c_rate_legacy_phyctl(uint rate); ++ ++extern void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams); ++extern void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset); ++extern void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, ++ u8 txstreams); ++extern void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, ++ u8 bw); ++ ++#endif /* _BRCM_RATE_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/scb.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/scb.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/scb.h.orig 2011-11-09 13:46:58.284800145 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/scb.h 2011-11-09 13:47:17.043565628 -0500 +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_SCB_H_ ++#define _BRCM_SCB_H_ ++ ++#include ++#include ++#include ++#include "types.h" ++ ++#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */ ++ ++#define AMPDU_MAX_SCB_TID NUMPRIO ++ ++/* scb flags */ ++#define SCB_WMECAP 0x0040 ++#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */ ++#define SCB_IS40 0x80000 /* 40MHz capable */ ++#define SCB_STBCCAP 0x40000000 /* STBC Capable */ ++ ++#define SCB_MAGIC 0xbeefcafe ++ ++/* structure to store per-tid state for the ampdu initiator */ ++struct scb_ampdu_tid_ini { ++ u8 tx_in_transit; /* number of pending mpdus in transit in driver */ ++ u8 tid; /* initiator tid for easy lookup */ ++ /* tx retry count; indexed by seq modulo */ ++ u8 txretry[AMPDU_TX_BA_MAX_WSIZE]; ++ struct scb *scb; /* backptr for easy lookup */ ++ u8 ba_wsize; /* negotiated ba window size (in pdu) */ ++}; ++ ++struct scb_ampdu { ++ struct scb *scb; /* back pointer for easy reference */ ++ u8 mpdu_density; /* mpdu density */ ++ u8 max_pdu; /* max pdus allowed in ampdu */ ++ u8 release; /* # of mpdus released at a time */ ++ u16 min_len; /* min mpdu len to support the density */ ++ u32 max_rx_ampdu_bytes; /* max ampdu rcv length; 8k, 16k, 32k, 64k */ ++ ++ /* ++ * This could easily be a ini[] pointer and we keep this info in wl ++ * itself instead of having mac80211 hold it for us. Also could be made ++ * dynamic per tid instead of static. ++ */ ++ /* initiator info - per tid (NUMPRIO): */ ++ struct scb_ampdu_tid_ini ini[AMPDU_MAX_SCB_TID]; ++}; ++ ++/* station control block - one per remote MAC address */ ++struct scb { ++ u32 magic; ++ u32 flags; /* various bit flags as defined below */ ++ u32 flags2; /* various bit flags2 as defined below */ ++ u8 state; /* current state bitfield of auth/assoc process */ ++ u8 ea[ETH_ALEN]; /* station address */ ++ uint fragresid[NUMPRIO];/* #bytes unused in frag buffer per prio */ ++ ++ u16 seqctl[NUMPRIO]; /* seqctl of last received frame (for dups) */ ++ /* seqctl of last received frame (for dups) for non-QoS data and ++ * management */ ++ u16 seqctl_nonqos; ++ u16 seqnum[NUMPRIO];/* WME: driver maintained sw seqnum per priority */ ++ ++ struct scb_ampdu scb_ampdu; /* AMPDU state including per tid info */ ++}; ++ ++#endif /* _BRCM_SCB_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.c.orig 2011-11-09 13:46:58.285800133 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.c 2011-11-09 13:47:17.044565616 -0500 +@@ -0,0 +1,1298 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "pub.h" ++#include "nicpci.h" ++#include "aiutils.h" ++#include "otp.h" ++#include "srom.h" ++ ++/* ++ * SROM CRC8 polynomial value: ++ * ++ * x^8 + x^7 +x^6 + x^4 + x^2 + 1 ++ */ ++#define SROM_CRC8_POLY 0xAB ++ ++/* Maximum srom: 6 Kilobits == 768 bytes */ ++#define SROM_MAX 768 ++ ++/* PCI fields */ ++#define PCI_F0DEVID 48 ++ ++#define SROM_WORDS 64 ++ ++#define SROM_SSID 2 ++ ++#define SROM_WL1LHMAXP 29 ++ ++#define SROM_WL1LPAB0 30 ++#define SROM_WL1LPAB1 31 ++#define SROM_WL1LPAB2 32 ++ ++#define SROM_WL1HPAB0 33 ++#define SROM_WL1HPAB1 34 ++#define SROM_WL1HPAB2 35 ++ ++#define SROM_MACHI_IL0 36 ++#define SROM_MACMID_IL0 37 ++#define SROM_MACLO_IL0 38 ++#define SROM_MACHI_ET1 42 ++#define SROM_MACMID_ET1 43 ++#define SROM_MACLO_ET1 44 ++#define SROM3_MACHI 37 ++#define SROM3_MACMID 38 ++#define SROM3_MACLO 39 ++ ++#define SROM_BXARSSI2G 40 ++#define SROM_BXARSSI5G 41 ++ ++#define SROM_TRI52G 42 ++#define SROM_TRI5GHL 43 ++ ++#define SROM_RXPO52G 45 ++ ++#define SROM_AABREV 46 ++/* Fields in AABREV */ ++#define SROM_BR_MASK 0x00ff ++#define SROM_CC_MASK 0x0f00 ++#define SROM_CC_SHIFT 8 ++#define SROM_AA0_MASK 0x3000 ++#define SROM_AA0_SHIFT 12 ++#define SROM_AA1_MASK 0xc000 ++#define SROM_AA1_SHIFT 14 ++ ++#define SROM_WL0PAB0 47 ++#define SROM_WL0PAB1 48 ++#define SROM_WL0PAB2 49 ++ ++#define SROM_LEDBH10 50 ++#define SROM_LEDBH32 51 ++ ++#define SROM_WL10MAXP 52 ++ ++#define SROM_WL1PAB0 53 ++#define SROM_WL1PAB1 54 ++#define SROM_WL1PAB2 55 ++ ++#define SROM_ITT 56 ++ ++#define SROM_BFL 57 ++#define SROM_BFL2 28 ++#define SROM3_BFL2 61 ++ ++#define SROM_AG10 58 ++ ++#define SROM_CCODE 59 ++ ++#define SROM_OPO 60 ++ ++#define SROM3_LEDDC 62 ++ ++#define SROM_CRCREV 63 ++ ++/* SROM Rev 4: Reallocate the software part of the srom to accommodate ++ * MIMO features. It assumes up to two PCIE functions and 440 bytes ++ * of usable srom i.e. the usable storage in chips with OTP that ++ * implements hardware redundancy. ++ */ ++ ++#define SROM4_WORDS 220 ++ ++#define SROM4_SIGN 32 ++#define SROM4_SIGNATURE 0x5372 ++ ++#define SROM4_BREV 33 ++ ++#define SROM4_BFL0 34 ++#define SROM4_BFL1 35 ++#define SROM4_BFL2 36 ++#define SROM4_BFL3 37 ++#define SROM5_BFL0 37 ++#define SROM5_BFL1 38 ++#define SROM5_BFL2 39 ++#define SROM5_BFL3 40 ++ ++#define SROM4_MACHI 38 ++#define SROM4_MACMID 39 ++#define SROM4_MACLO 40 ++#define SROM5_MACHI 41 ++#define SROM5_MACMID 42 ++#define SROM5_MACLO 43 ++ ++#define SROM4_CCODE 41 ++#define SROM4_REGREV 42 ++#define SROM5_CCODE 34 ++#define SROM5_REGREV 35 ++ ++#define SROM4_LEDBH10 43 ++#define SROM4_LEDBH32 44 ++#define SROM5_LEDBH10 59 ++#define SROM5_LEDBH32 60 ++ ++#define SROM4_LEDDC 45 ++#define SROM5_LEDDC 45 ++ ++#define SROM4_AA 46 ++ ++#define SROM4_AG10 47 ++#define SROM4_AG32 48 ++ ++#define SROM4_TXPID2G 49 ++#define SROM4_TXPID5G 51 ++#define SROM4_TXPID5GL 53 ++#define SROM4_TXPID5GH 55 ++ ++#define SROM4_TXRXC 61 ++#define SROM4_TXCHAIN_MASK 0x000f ++#define SROM4_TXCHAIN_SHIFT 0 ++#define SROM4_RXCHAIN_MASK 0x00f0 ++#define SROM4_RXCHAIN_SHIFT 4 ++#define SROM4_SWITCH_MASK 0xff00 ++#define SROM4_SWITCH_SHIFT 8 ++ ++/* Per-path fields */ ++#define MAX_PATH_SROM 4 ++#define SROM4_PATH0 64 ++#define SROM4_PATH1 87 ++#define SROM4_PATH2 110 ++#define SROM4_PATH3 133 ++ ++#define SROM4_2G_ITT_MAXP 0 ++#define SROM4_2G_PA 1 ++#define SROM4_5G_ITT_MAXP 5 ++#define SROM4_5GLH_MAXP 6 ++#define SROM4_5G_PA 7 ++#define SROM4_5GL_PA 11 ++#define SROM4_5GH_PA 15 ++ ++/* All the miriad power offsets */ ++#define SROM4_2G_CCKPO 156 ++#define SROM4_2G_OFDMPO 157 ++#define SROM4_5G_OFDMPO 159 ++#define SROM4_5GL_OFDMPO 161 ++#define SROM4_5GH_OFDMPO 163 ++#define SROM4_2G_MCSPO 165 ++#define SROM4_5G_MCSPO 173 ++#define SROM4_5GL_MCSPO 181 ++#define SROM4_5GH_MCSPO 189 ++#define SROM4_CDDPO 197 ++#define SROM4_STBCPO 198 ++#define SROM4_BW40PO 199 ++#define SROM4_BWDUPPO 200 ++ ++#define SROM4_CRCREV 219 ++ ++/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. ++ * This is acombined srom for both MIMO and SISO boards, usable in ++ * the .130 4Kilobit OTP with hardware redundancy. ++ */ ++#define SROM8_BREV 65 ++ ++#define SROM8_BFL0 66 ++#define SROM8_BFL1 67 ++#define SROM8_BFL2 68 ++#define SROM8_BFL3 69 ++ ++#define SROM8_MACHI 70 ++#define SROM8_MACMID 71 ++#define SROM8_MACLO 72 ++ ++#define SROM8_CCODE 73 ++#define SROM8_REGREV 74 ++ ++#define SROM8_LEDBH10 75 ++#define SROM8_LEDBH32 76 ++ ++#define SROM8_LEDDC 77 ++ ++#define SROM8_AA 78 ++ ++#define SROM8_AG10 79 ++#define SROM8_AG32 80 ++ ++#define SROM8_TXRXC 81 ++ ++#define SROM8_BXARSSI2G 82 ++#define SROM8_BXARSSI5G 83 ++#define SROM8_TRI52G 84 ++#define SROM8_TRI5GHL 85 ++#define SROM8_RXPO52G 86 ++ ++#define SROM8_FEM2G 87 ++#define SROM8_FEM5G 88 ++#define SROM8_FEM_ANTSWLUT_MASK 0xf800 ++#define SROM8_FEM_ANTSWLUT_SHIFT 11 ++#define SROM8_FEM_TR_ISO_MASK 0x0700 ++#define SROM8_FEM_TR_ISO_SHIFT 8 ++#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 ++#define SROM8_FEM_PDET_RANGE_SHIFT 3 ++#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 ++#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 ++#define SROM8_FEM_TSSIPOS_MASK 0x0001 ++#define SROM8_FEM_TSSIPOS_SHIFT 0 ++ ++#define SROM8_THERMAL 89 ++ ++/* Temp sense related entries */ ++#define SROM8_MPWR_RAWTS 90 ++#define SROM8_TS_SLP_OPT_CORRX 91 ++/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, ++ * IQSWP: IQ CAL swap disable */ ++#define SROM8_FOC_HWIQ_IQSWP 92 ++ ++/* Temperature delta for PHY calibration */ ++#define SROM8_PHYCAL_TEMPDELTA 93 ++ ++/* Per-path offsets & fields */ ++#define SROM8_PATH0 96 ++#define SROM8_PATH1 112 ++#define SROM8_PATH2 128 ++#define SROM8_PATH3 144 ++ ++#define SROM8_2G_ITT_MAXP 0 ++#define SROM8_2G_PA 1 ++#define SROM8_5G_ITT_MAXP 4 ++#define SROM8_5GLH_MAXP 5 ++#define SROM8_5G_PA 6 ++#define SROM8_5GL_PA 9 ++#define SROM8_5GH_PA 12 ++ ++/* All the miriad power offsets */ ++#define SROM8_2G_CCKPO 160 ++ ++#define SROM8_2G_OFDMPO 161 ++#define SROM8_5G_OFDMPO 163 ++#define SROM8_5GL_OFDMPO 165 ++#define SROM8_5GH_OFDMPO 167 ++ ++#define SROM8_2G_MCSPO 169 ++#define SROM8_5G_MCSPO 177 ++#define SROM8_5GL_MCSPO 185 ++#define SROM8_5GH_MCSPO 193 ++ ++#define SROM8_CDDPO 201 ++#define SROM8_STBCPO 202 ++#define SROM8_BW40PO 203 ++#define SROM8_BWDUPPO 204 ++ ++/* SISO PA parameters are in the path0 spaces */ ++#define SROM8_SISO 96 ++ ++/* Legacy names for SISO PA paramters */ ++#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) ++#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) ++#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) ++#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) ++#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) ++#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) ++#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) ++#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) ++#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) ++#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) ++#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) ++#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) ++#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) ++#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) ++#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) ++ ++/* SROM REV 9 */ ++#define SROM9_2GPO_CCKBW20 160 ++#define SROM9_2GPO_CCKBW20UL 161 ++#define SROM9_2GPO_LOFDMBW20 162 ++#define SROM9_2GPO_LOFDMBW20UL 164 ++ ++#define SROM9_5GLPO_LOFDMBW20 166 ++#define SROM9_5GLPO_LOFDMBW20UL 168 ++#define SROM9_5GMPO_LOFDMBW20 170 ++#define SROM9_5GMPO_LOFDMBW20UL 172 ++#define SROM9_5GHPO_LOFDMBW20 174 ++#define SROM9_5GHPO_LOFDMBW20UL 176 ++ ++#define SROM9_2GPO_MCSBW20 178 ++#define SROM9_2GPO_MCSBW20UL 180 ++#define SROM9_2GPO_MCSBW40 182 ++ ++#define SROM9_5GLPO_MCSBW20 184 ++#define SROM9_5GLPO_MCSBW20UL 186 ++#define SROM9_5GLPO_MCSBW40 188 ++#define SROM9_5GMPO_MCSBW20 190 ++#define SROM9_5GMPO_MCSBW20UL 192 ++#define SROM9_5GMPO_MCSBW40 194 ++#define SROM9_5GHPO_MCSBW20 196 ++#define SROM9_5GHPO_MCSBW20UL 198 ++#define SROM9_5GHPO_MCSBW40 200 ++ ++#define SROM9_PO_MCS32 202 ++#define SROM9_PO_LOFDM40DUP 203 ++ ++/* SROM flags (see sromvar_t) */ ++ ++/* value continues as described by the next entry */ ++#define SRFL_MORE 1 ++#define SRFL_NOFFS 2 /* value bits can't be all one's */ ++#define SRFL_PRHEX 4 /* value is in hexdecimal format */ ++#define SRFL_PRSIGN 8 /* value is in signed decimal format */ ++#define SRFL_CCODE 0x10 /* value is in country code format */ ++#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ ++#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ ++/* do not generate a nvram param, entry is for mfgc */ ++#define SRFL_NOVAR 0x80 ++ ++/* Max. nvram variable table size */ ++#define MAXSZ_NVRAM_VARS 4096 ++ ++/* ++ * indicates type of value. ++ */ ++enum brcms_srom_var_type { ++ BRCMS_SROM_STRING, ++ BRCMS_SROM_SNUMBER, ++ BRCMS_SROM_UNUMBER ++}; ++ ++/* ++ * storage type for srom variable. ++ * ++ * var_list: for linked list operations. ++ * varid: identifier of the variable. ++ * var_type: type of variable. ++ * buf: variable value when var_type == BRCMS_SROM_STRING. ++ * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER. ++ * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER. ++ */ ++struct brcms_srom_list_head { ++ struct list_head var_list; ++ enum brcms_srom_id varid; ++ enum brcms_srom_var_type var_type; ++ union { ++ char buf[0]; ++ u32 uval; ++ s32 sval; ++ }; ++}; ++ ++struct brcms_sromvar { ++ enum brcms_srom_id varid; ++ u32 revmask; ++ u32 flags; ++ u16 off; ++ u16 mask; ++}; ++ ++struct brcms_varbuf { ++ char *base; /* pointer to buffer base */ ++ char *buf; /* pointer to current position */ ++ unsigned int size; /* current (residual) size in bytes */ ++}; ++ ++/* ++ * Assumptions: ++ * - Ethernet address spans across 3 consecutive words ++ * ++ * Table rules: ++ * - Add multiple entries next to each other if a value spans across multiple ++ * words (even multiple fields in the same word) with each entry except the ++ * last having it's SRFL_MORE bit set. ++ * - Ethernet address entry does not follow above rule and must not have ++ * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words. ++ * - The last entry's name field must be NULL to indicate the end of the table. ++ * Other entries must have non-NULL name. ++ */ ++static const struct brcms_sromvar pci_sromvars[] = { ++ {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, ++ 0xffff}, ++ {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV, ++ SROM_BR_MASK}, ++ {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, ++ {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff}, ++ {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff}, ++ {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, ++ {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, ++ {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff}, ++ {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff}, ++ {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff}, ++ {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff}, ++ {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, ++ {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00}, ++ {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff}, ++ {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff}, ++ {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff}, ++ {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, ++ {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, ++ {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, ++ {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, ++ {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, ++ {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, ++ {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, ++ {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, ++ {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, ++ {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, ++ {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, ++ {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, ++ {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, ++ {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, ++ {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, ++ {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, ++ {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, ++ {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, ++ {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, ++ {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff}, ++ {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, ++ {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, ++ {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, ++ {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, ++ {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, ++ {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff}, ++ {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff}, ++ {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff}, ++ {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, ++ {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff}, ++ {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff}, ++ {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, ++ {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00}, ++ {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00}, ++ {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff}, ++ {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00}, ++ {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff}, ++ {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00}, ++ {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff}, ++ {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00}, ++ {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff}, ++ {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00}, ++ {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff}, ++ {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00}, ++ {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, ++ {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, ++ {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, ++ {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, ++ {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, ++ {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, ++ {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, ++ {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, ++ {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, ++ {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00}, ++ {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, ++ {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, ++ {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, ++ {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, ++ {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, ++ {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, ++ {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, ++ {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, ++ {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, ++ {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, ++ {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, ++ {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, ++ {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, ++ {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff}, ++ {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, ++ {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, ++ {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, ++ {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, ++ {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, ++ {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, ++ {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, ++ {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, ++ {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, ++ {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, ++ {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, ++ {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, ++ {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, ++ {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, ++ {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, ++ {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, ++ {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, ++ {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, ++ {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff}, ++ {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00}, ++ {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, ++ {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00}, ++ {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff}, ++ {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00}, ++ {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff}, ++ {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, ++ {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, ++ {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, ++ {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, ++ {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, ++ {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, ++ SROM4_TXCHAIN_MASK}, ++ {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, ++ SROM4_RXCHAIN_MASK}, ++ {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, ++ SROM4_SWITCH_MASK}, ++ {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, ++ SROM4_TXCHAIN_MASK}, ++ {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, ++ SROM4_RXCHAIN_MASK}, ++ {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, ++ SROM4_SWITCH_MASK}, ++ {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G, ++ SROM8_FEM_TSSIPOS_MASK}, ++ {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G, ++ SROM8_FEM_EXTPA_GAIN_MASK}, ++ {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G, ++ SROM8_FEM_PDET_RANGE_MASK}, ++ {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, ++ {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G, ++ SROM8_FEM_ANTSWLUT_MASK}, ++ {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G, ++ SROM8_FEM_TSSIPOS_MASK}, ++ {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G, ++ SROM8_FEM_EXTPA_GAIN_MASK}, ++ {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G, ++ SROM8_FEM_PDET_RANGE_MASK}, ++ {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, ++ {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G, ++ SROM8_FEM_ANTSWLUT_MASK}, ++ {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00}, ++ {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff}, ++ {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, ++ {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, ++ {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, ++ {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, ++ {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, ++ {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, ++ {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, ++ {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, ++ {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, ++ {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, ++ {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, ++ {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, ++ {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, ++ {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, ++ {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, ++ {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, ++ ++ {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, ++ {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, ++ {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, ++ {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, ++ {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, ++ {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, ++ {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, ++ {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, ++ {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, ++ 0xffff}, ++ {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, ++ 0xffff}, ++ {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, ++ 0xffff}, ++ {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, ++ 0xffff}, ++ {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, ++ 0xffff}, ++ {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, ++ 0xffff}, ++ {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, ++ 0x01ff}, ++ {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, ++ 0xfe00}, ++ {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX, ++ SROM8_TS_SLP_OPT_CORRX, 0x00ff}, ++ {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, ++ 0xfc00}, ++ {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX, ++ SROM8_TS_SLP_OPT_CORRX, 0x0300}, ++ {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX, ++ SROM8_FOC_HWIQ_IQSWP, 0x000f}, ++ {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, ++ 0x0010}, ++ {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, ++ 0x0020}, ++ {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, ++ 0x00ff}, ++ ++ {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, ++ {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, ++ {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, ++ {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, ++ {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff}, ++ {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff}, ++ {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff}, ++ {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, ++ {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff}, ++ {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff}, ++ {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff}, ++ {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, ++ ++ /* power per rate from sromrev 9 */ ++ {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff}, ++ {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE, ++ SROM9_2GPO_LOFDMBW20, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE, ++ SROM9_2GPO_LOFDMBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GLPO_LOFDMBW20, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GLPO_LOFDMBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GMPO_LOFDMBW20, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GMPO_LOFDMBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GHPO_LOFDMBW20, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, ++ {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GHPO_LOFDMBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GLPO_MCSBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GMPO_MCSBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE, ++ SROM9_5GHPO_MCSBW20UL, 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, ++ {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, ++ 0xffff}, ++ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, ++ {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff}, ++ {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff}, ++ ++ {BRCMS_SROM_NULL, 0, 0, 0, 0} ++}; ++ ++static const struct brcms_sromvar perpath_pci_sromvars[] = { ++ {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, ++ {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, ++ {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, ++ {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, ++ {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, ++ {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, ++ {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, ++ {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, ++ {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, ++ {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, ++ {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, ++ {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, ++ {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, ++ {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, ++ {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, ++ {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, ++ 0xffff}, ++ {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, ++ 0xffff}, ++ {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, ++ 0xffff}, ++ {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, ++ {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, ++ 0xffff}, ++ {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, ++ 0xffff}, ++ {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, ++ 0xffff}, ++ {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff}, ++ {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, ++ {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, ++ {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, ++ {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, ++ {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, ++ {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff}, ++ {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff}, ++ {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, ++ {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, ++ {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, ++ {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, ++ {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, ++ {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, ++ 0xffff}, ++ {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, ++ 0xffff}, ++ {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, ++ {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, ++ 0xffff}, ++ {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, ++ 0xffff}, ++ {BRCMS_SROM_NULL, 0, 0, 0, 0} ++}; ++ ++/* crc table has the same contents for every device instance, so it can be ++ * shared between devices. */ ++static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE]; ++ ++static u16 __iomem * ++srom_window_address(struct si_pub *sih, u8 __iomem *curmap) ++{ ++ if (sih->ccrev < 32) ++ return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET); ++ if (sih->cccaps & CC_CAP_SROM) ++ return (u16 __iomem *) ++ (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP); ++ ++ return NULL; ++} ++ ++/* Parse SROM and create name=value pairs. 'srom' points to ++ * the SROM word array. 'off' specifies the offset of the ++ * first word 'srom' points to, which should be either 0 or ++ * SROM3_SWRG_OFF (full SROM or software region). ++ */ ++ ++static uint mask_shift(u16 mask) ++{ ++ uint i; ++ for (i = 0; i < (sizeof(mask) << 3); i++) { ++ if (mask & (1 << i)) ++ return i; ++ } ++ return 0; ++} ++ ++static uint mask_width(u16 mask) ++{ ++ int i; ++ for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) { ++ if (mask & (1 << i)) ++ return (uint) (i - mask_shift(mask) + 1); ++ } ++ return 0; ++} ++ ++static inline void ltoh16_buf(u16 *buf, unsigned int size) ++{ ++ size /= 2; ++ while (size--) ++ *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size)); ++} ++ ++static inline void htol16_buf(u16 *buf, unsigned int size) ++{ ++ size /= 2; ++ while (size--) ++ *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size)); ++} ++ ++/* ++ * convert binary srom data into linked list of srom variable items. ++ */ ++static void ++_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) ++{ ++ struct brcms_srom_list_head *entry; ++ enum brcms_srom_id id; ++ u16 w; ++ u32 val; ++ const struct brcms_sromvar *srv; ++ uint width; ++ uint flags; ++ u32 sr = (1 << sromrev); ++ ++ /* first store the srom revision */ ++ entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL); ++ entry->varid = BRCMS_SROM_REV; ++ entry->var_type = BRCMS_SROM_UNUMBER; ++ entry->uval = sromrev; ++ list_add(&entry->var_list, var_list); ++ ++ for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) { ++ enum brcms_srom_var_type type; ++ u8 ea[ETH_ALEN]; ++ u8 extra_space = 0; ++ ++ if ((srv->revmask & sr) == 0) ++ continue; ++ ++ flags = srv->flags; ++ id = srv->varid; ++ ++ /* This entry is for mfgc only. Don't generate param for it, */ ++ if (flags & SRFL_NOVAR) ++ continue; ++ ++ if (flags & SRFL_ETHADDR) { ++ /* ++ * stored in string format XX:XX:XX:XX:XX:XX (17 chars) ++ */ ++ ea[0] = (srom[srv->off] >> 8) & 0xff; ++ ea[1] = srom[srv->off] & 0xff; ++ ea[2] = (srom[srv->off + 1] >> 8) & 0xff; ++ ea[3] = srom[srv->off + 1] & 0xff; ++ ea[4] = (srom[srv->off + 2] >> 8) & 0xff; ++ ea[5] = srom[srv->off + 2] & 0xff; ++ /* 17 characters + string terminator - union size */ ++ extra_space = 18 - sizeof(s32); ++ type = BRCMS_SROM_STRING; ++ } else { ++ w = srom[srv->off]; ++ val = (w & srv->mask) >> mask_shift(srv->mask); ++ width = mask_width(srv->mask); ++ ++ while (srv->flags & SRFL_MORE) { ++ srv++; ++ if (srv->off == 0) ++ continue; ++ ++ w = srom[srv->off]; ++ val += ++ ((w & srv->mask) >> mask_shift(srv-> ++ mask)) << ++ width; ++ width += mask_width(srv->mask); ++ } ++ ++ if ((flags & SRFL_NOFFS) ++ && ((int)val == (1 << width) - 1)) ++ continue; ++ ++ if (flags & SRFL_CCODE) { ++ type = BRCMS_SROM_STRING; ++ } else if (flags & SRFL_LEDDC) { ++ /* LED Powersave duty cycle has to be scaled: ++ *(oncount >> 24) (offcount >> 8) ++ */ ++ u32 w32 = /* oncount */ ++ (((val >> 8) & 0xff) << 24) | ++ /* offcount */ ++ (((val & 0xff)) << 8); ++ type = BRCMS_SROM_UNUMBER; ++ val = w32; ++ } else if ((flags & SRFL_PRSIGN) ++ && (val & (1 << (width - 1)))) { ++ type = BRCMS_SROM_SNUMBER; ++ val |= ~0 << width; ++ } else ++ type = BRCMS_SROM_UNUMBER; ++ } ++ ++ entry = kzalloc(sizeof(struct brcms_srom_list_head) + ++ extra_space, GFP_KERNEL); ++ entry->varid = id; ++ entry->var_type = type; ++ if (flags & SRFL_ETHADDR) { ++ snprintf(entry->buf, 18, "%pM", ea); ++ } else if (flags & SRFL_CCODE) { ++ if (val == 0) ++ entry->buf[0] = '\0'; ++ else ++ snprintf(entry->buf, 3, "%c%c", ++ (val >> 8), (val & 0xff)); ++ } else { ++ entry->uval = val; ++ } ++ ++ list_add(&entry->var_list, var_list); ++ } ++ ++ if (sromrev >= 4) { ++ /* Do per-path variables */ ++ uint p, pb, psz; ++ ++ if (sromrev >= 8) { ++ pb = SROM8_PATH0; ++ psz = SROM8_PATH1 - SROM8_PATH0; ++ } else { ++ pb = SROM4_PATH0; ++ psz = SROM4_PATH1 - SROM4_PATH0; ++ } ++ ++ for (p = 0; p < MAX_PATH_SROM; p++) { ++ for (srv = perpath_pci_sromvars; ++ srv->varid != BRCMS_SROM_NULL; srv++) { ++ if ((srv->revmask & sr) == 0) ++ continue; ++ ++ if (srv->flags & SRFL_NOVAR) ++ continue; ++ ++ w = srom[pb + srv->off]; ++ val = (w & srv->mask) >> mask_shift(srv->mask); ++ width = mask_width(srv->mask); ++ ++ /* Cheating: no per-path var is more than ++ * 1 word */ ++ if ((srv->flags & SRFL_NOFFS) ++ && ((int)val == (1 << width) - 1)) ++ continue; ++ ++ entry = ++ kzalloc(sizeof(struct brcms_srom_list_head), ++ GFP_KERNEL); ++ entry->varid = srv->varid+p; ++ entry->var_type = BRCMS_SROM_UNUMBER; ++ entry->uval = val; ++ list_add(&entry->var_list, var_list); ++ } ++ pb += psz; ++ } ++ } ++} ++ ++/* ++ * Read in and validate sprom. ++ * Return 0 on success, nonzero on error. ++ */ ++static int ++sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff, ++ u16 *buf, uint nwords, bool check_crc) ++{ ++ int err = 0; ++ uint i; ++ ++ /* read the sprom */ ++ for (i = 0; i < nwords; i++) ++ buf[i] = R_REG(&sprom[wordoff + i]); ++ ++ if (check_crc) { ++ ++ if (buf[0] == 0xffff) ++ /* ++ * The hardware thinks that an srom that starts with ++ * 0xffff is blank, regardless of the rest of the ++ * content, so declare it bad. ++ */ ++ return -ENODATA; ++ ++ /* fixup the endianness so crc8 will pass */ ++ htol16_buf(buf, nwords * 2); ++ if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2, ++ CRC8_INIT_VALUE) != ++ CRC8_GOOD_VALUE(brcms_srom_crc8_table)) ++ /* DBG only pci always read srom4 first, then srom8/9 */ ++ err = -EIO; ++ ++ /* now correct the endianness of the byte array */ ++ ltoh16_buf(buf, nwords * 2); ++ } ++ return err; ++} ++ ++static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz) ++{ ++ u8 *otp; ++ uint sz = OTP_SZ_MAX / 2; /* size in words */ ++ int err = 0; ++ ++ otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC); ++ if (otp == NULL) ++ return -ENOMEM; ++ ++ err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz); ++ ++ memcpy(buf, otp, bufsz); ++ ++ kfree(otp); ++ ++ /* Check CRC */ ++ if (buf[0] == 0xffff) ++ /* The hardware thinks that an srom that starts with 0xffff ++ * is blank, regardless of the rest of the content, so declare ++ * it bad. ++ */ ++ return -ENODATA; ++ ++ /* fixup the endianness so crc8 will pass */ ++ htol16_buf(buf, bufsz); ++ if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2, ++ CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table)) ++ err = -EIO; ++ ++ /* now correct the endianness of the byte array */ ++ ltoh16_buf(buf, bufsz); ++ ++ return err; ++} ++ ++/* ++ * Initialize nonvolatile variable table from sprom. ++ * Return 0 on success, nonzero on error. ++ */ ++static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap) ++{ ++ u16 *srom; ++ u16 __iomem *sromwindow; ++ u8 sromrev = 0; ++ u32 sr; ++ int err = 0; ++ ++ /* ++ * Apply CRC over SROM content regardless SROM is present or not. ++ */ ++ srom = kmalloc(SROM_MAX, GFP_ATOMIC); ++ if (!srom) ++ return -ENOMEM; ++ ++ sromwindow = srom_window_address(sih, curmap); ++ ++ crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY); ++ if (ai_is_sprom_available(sih)) { ++ err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS, ++ true); ++ ++ if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) || ++ (((sih->buscoretype == PCIE_CORE_ID) ++ && (sih->buscorerev >= 6)) ++ || ((sih->buscoretype == PCI_CORE_ID) ++ && (sih->buscorerev >= 0xe)))) { ++ /* sromrev >= 4, read more */ ++ err = sprom_read_pci(sih, sromwindow, 0, srom, ++ SROM4_WORDS, true); ++ sromrev = srom[SROM4_CRCREV] & 0xff; ++ } else if (err == 0) { ++ /* srom is good and is rev < 4 */ ++ /* top word of sprom contains version and crc8 */ ++ sromrev = srom[SROM_CRCREV] & 0xff; ++ /* bcm4401 sroms misprogrammed */ ++ if (sromrev == 0x10) ++ sromrev = 1; ++ } ++ } else { ++ /* Use OTP if SPROM not available */ ++ err = otp_read_pci(sih, srom, SROM_MAX); ++ if (err == 0) ++ /* OTP only contain SROM rev8/rev9 for now */ ++ sromrev = srom[SROM4_CRCREV] & 0xff; ++ } ++ ++ if (!err) { ++ struct si_info *sii = (struct si_info *)sih; ++ ++ /* Bitmask for the sromrev */ ++ sr = 1 << sromrev; ++ ++ /* ++ * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, ++ * 9 ++ */ ++ if ((sr & 0x33e) == 0) { ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ INIT_LIST_HEAD(&sii->var_list); ++ ++ /* parse SROM into name=value pairs. */ ++ _initvars_srom_pci(sromrev, srom, &sii->var_list); ++ } ++ ++errout: ++ kfree(srom); ++ return err; ++} ++ ++void srom_free_vars(struct si_pub *sih) ++{ ++ struct si_info *sii; ++ struct brcms_srom_list_head *entry, *next; ++ ++ sii = (struct si_info *)sih; ++ list_for_each_entry_safe(entry, next, &sii->var_list, var_list) { ++ list_del(&entry->var_list); ++ kfree(entry); ++ } ++} ++/* ++ * Initialize local vars from the right source for this platform. ++ * Return 0 on success, nonzero on error. ++ */ ++int srom_var_init(struct si_pub *sih, void __iomem *curmap) ++{ ++ uint len; ++ ++ len = 0; ++ ++ if (curmap != NULL) ++ return initvars_srom_pci(sih, curmap); ++ ++ return -EINVAL; ++} ++ ++/* ++ * Search the name=value vars for a specific one and return its value. ++ * Returns NULL if not found. ++ */ ++char *getvar(struct si_pub *sih, enum brcms_srom_id id) ++{ ++ struct si_info *sii; ++ struct brcms_srom_list_head *entry; ++ ++ sii = (struct si_info *)sih; ++ ++ list_for_each_entry(entry, &sii->var_list, var_list) ++ if (entry->varid == id) ++ return &entry->buf[0]; ++ ++ /* nothing found */ ++ return NULL; ++} ++ ++/* ++ * Search the vars for a specific one and return its value as ++ * an integer. Returns 0 if not found.- ++ */ ++int getintvar(struct si_pub *sih, enum brcms_srom_id id) ++{ ++ struct si_info *sii; ++ struct brcms_srom_list_head *entry; ++ unsigned long res; ++ ++ sii = (struct si_info *)sih; ++ ++ list_for_each_entry(entry, &sii->var_list, var_list) ++ if (entry->varid == id) { ++ if (entry->var_type == BRCMS_SROM_SNUMBER || ++ entry->var_type == BRCMS_SROM_UNUMBER) ++ return (int)entry->sval; ++ else if (!kstrtoul(&entry->buf[0], 0, &res)) ++ return (int)res; ++ } ++ ++ return 0; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.h.orig 2011-11-09 13:46:58.285800133 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/srom.h 2011-11-09 13:47:17.044565616 -0500 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_SROM_H_ ++#define _BRCM_SROM_H_ ++ ++#include "types.h" ++ ++/* Prototypes */ ++extern int srom_var_init(struct si_pub *sih, void __iomem *curmap); ++extern void srom_free_vars(struct si_pub *sih); ++ ++extern int srom_read(struct si_pub *sih, uint bus, void *curmap, ++ uint byteoff, uint nbytes, u16 *buf, bool check_crc); ++ ++/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP ++ * and extract from it into name=value pairs ++ */ ++extern int srom_parsecis(u8 **pcis, uint ciscnt, ++ char **vars, uint *count); ++#endif /* _BRCM_SROM_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.c.orig 2011-11-09 13:46:58.286800121 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.c 2011-11-09 13:47:17.045565604 -0500 +@@ -0,0 +1,436 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++ ++#include "types.h" ++#include "d11.h" ++#include "rate.h" ++#include "phy/phy_hal.h" ++#include "channel.h" ++#include "main.h" ++#include "stf.h" ++ ++#define MIN_SPATIAL_EXPANSION 0 ++#define MAX_SPATIAL_EXPANSION 1 ++ ++#define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \ ++ NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6)) ++ ++#define NSTS_1 1 ++#define NSTS_2 2 ++#define NSTS_3 3 ++#define NSTS_4 4 ++ ++static const u8 txcore_default[5] = { ++ (0), /* bitmap of the core enabled */ ++ (0x01), /* For Nsts = 1, enable core 1 */ ++ (0x03), /* For Nsts = 2, enable core 1 & 2 */ ++ (0x07), /* For Nsts = 3, enable core 1, 2 & 3 */ ++ (0x0f) /* For Nsts = 4, enable all cores */ ++}; ++ ++static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val) ++{ ++ /* MIMOPHYs rev3-6 cannot receive STBC with only one rx core active */ ++ if (BRCMS_STF_SS_STBC_RX(wlc)) { ++ if ((wlc->stf->rxstreams == 1) && (val != HT_CAP_RX_STBC_NO)) ++ return; ++ } ++ ++ if (wlc->pub->up) { ++ brcms_c_update_beacon(wlc); ++ brcms_c_update_probe_resp(wlc, true); ++ } ++} ++ ++/* ++ * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to ++ * turn on/off txchain. ++ */ ++void brcms_c_tempsense_upd(struct brcms_c_info *wlc) ++{ ++ struct brcms_phy_pub *pi = wlc->band->pi; ++ uint active_chains, txchain; ++ ++ /* Check if the chip is too hot. Disable one Tx chain, if it is */ ++ /* high 4 bits are for Rx chain, low 4 bits are for Tx chain */ ++ active_chains = wlc_phy_stf_chain_active_get(pi); ++ txchain = active_chains & 0xf; ++ ++ if (wlc->stf->txchain == wlc->stf->hw_txchain) { ++ if (txchain && (txchain < wlc->stf->hw_txchain)) ++ /* turn off 1 tx chain */ ++ brcms_c_stf_txchain_set(wlc, txchain, true); ++ } else if (wlc->stf->txchain < wlc->stf->hw_txchain) { ++ if (txchain == wlc->stf->hw_txchain) ++ /* turn back on txchain */ ++ brcms_c_stf_txchain_set(wlc, txchain, true); ++ } ++} ++ ++void ++brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel, ++ u16 chanspec) ++{ ++ struct tx_power power; ++ u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; ++ ++ /* Clear previous settings */ ++ *ss_algo_channel = 0; ++ ++ if (!wlc->pub->up) { ++ *ss_algo_channel = (u16) -1; ++ return; ++ } ++ ++ wlc_phy_txpower_get_current(wlc->band->pi, &power, ++ CHSPEC_CHANNEL(chanspec)); ++ ++ siso_mcs_id = (CHSPEC_IS40(chanspec)) ? ++ WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_MCS20_SISO_FIRST; ++ cdd_mcs_id = (CHSPEC_IS40(chanspec)) ? ++ WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_MCS20_CDD_FIRST; ++ stbc_mcs_id = (CHSPEC_IS40(chanspec)) ? ++ WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_MCS20_STBC_FIRST; ++ ++ /* criteria to choose stf mode */ ++ ++ /* ++ * the "+3dbm (12 0.25db units)" is to account for the fact that with ++ * CDD, tx occurs on both chains ++ */ ++ if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12)) ++ setbit(ss_algo_channel, PHY_TXC1_MODE_SISO); ++ else ++ setbit(ss_algo_channel, PHY_TXC1_MODE_CDD); ++ ++ /* ++ * STBC is ORed into to algo channel as STBC requires per-packet SCB ++ * capability check so cannot be default mode of operation. One of ++ * SISO, CDD have to be set ++ */ ++ if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12)) ++ setbit(ss_algo_channel, PHY_TXC1_MODE_STBC); ++} ++ ++static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val) ++{ ++ if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) ++ return false; ++ ++ if ((int_val == ON) && (wlc->stf->txstreams == 1)) ++ return false; ++ ++ wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val; ++ wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val; ++ ++ return true; ++} ++ ++bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val) ++{ ++ if ((int_val != HT_CAP_RX_STBC_NO) ++ && (int_val != HT_CAP_RX_STBC_ONE_STREAM)) ++ return false; ++ ++ if (BRCMS_STF_SS_STBC_RX(wlc)) { ++ if ((int_val != HT_CAP_RX_STBC_NO) ++ && (wlc->stf->rxstreams == 1)) ++ return false; ++ } ++ ++ brcms_c_stf_stbc_rx_ht_update(wlc, int_val); ++ return true; ++} ++ ++static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts, ++ u8 core_mask) ++{ ++ BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n", ++ wlc->pub->unit, Nsts, core_mask); ++ ++ if (hweight8(core_mask) > wlc->stf->txstreams) ++ core_mask = 0; ++ ++ if ((hweight8(core_mask) == wlc->stf->txstreams) && ++ ((core_mask & ~wlc->stf->txchain) ++ || !(core_mask & wlc->stf->txchain))) ++ core_mask = wlc->stf->txchain; ++ ++ wlc->stf->txcore[Nsts] = core_mask; ++ /* Nsts = 1..4, txcore index = 1..4 */ ++ if (Nsts == 1) { ++ /* Needs to update beacon and ucode generated response ++ * frames when 1 stream core map changed ++ */ ++ wlc->stf->phytxant = core_mask << PHY_TXC_ANT_SHIFT; ++ brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); ++ if (wlc->clk) { ++ brcms_c_suspend_mac_and_wait(wlc); ++ brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec); ++ brcms_c_enable_mac(wlc); ++ } ++ } ++ ++ return 0; ++} ++ ++static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val) ++{ ++ int i; ++ u8 core_mask = 0; ++ ++ BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val); ++ ++ wlc->stf->spatial_policy = (s8) val; ++ for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) { ++ core_mask = (val == MAX_SPATIAL_EXPANSION) ? ++ wlc->stf->txchain : txcore_default[i]; ++ brcms_c_stf_txcore_set(wlc, (u8) i, core_mask); ++ } ++ return 0; ++} ++ ++/* ++ * Centralized txant update function. call it whenever wlc->stf->txant and/or ++ * wlc->stf->txchain change. ++ * ++ * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to ++ * achieve various tx/rx antenna selection schemes ++ * ++ * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 ++ * means auto(last rx). ++ * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 ++ * means last rx and do tx-antenna selection for SISO transmissions ++ * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7 ++ * means last rx and do tx-antenna selection for SISO transmissions ++ * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 ++ * means both cores active ++*/ ++static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) ++{ ++ s8 txant; ++ ++ txant = (s8) wlc->stf->txant; ++ if (BRCMS_PHY_11N_CAP(wlc->band)) { ++ if (txant == ANT_TX_FORCE_0) { ++ wlc->stf->phytxant = PHY_TXC_ANT_0; ++ } else if (txant == ANT_TX_FORCE_1) { ++ wlc->stf->phytxant = PHY_TXC_ANT_1; ++ ++ if (BRCMS_ISNPHY(wlc->band) && ++ NREV_GE(wlc->band->phyrev, 3) ++ && NREV_LT(wlc->band->phyrev, 7)) ++ wlc->stf->phytxant = PHY_TXC_ANT_2; ++ } else { ++ if (BRCMS_ISLCNPHY(wlc->band) || ++ BRCMS_ISSSLPNPHY(wlc->band)) ++ wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST; ++ else { ++ /* catch out of sync wlc->stf->txcore */ ++ WARN_ON(wlc->stf->txchain <= 0); ++ wlc->stf->phytxant = ++ wlc->stf->txchain << PHY_TXC_ANT_SHIFT; ++ } ++ } ++ } else { ++ if (txant == ANT_TX_FORCE_0) ++ wlc->stf->phytxant = PHY_TXC_OLD_ANT_0; ++ else if (txant == ANT_TX_FORCE_1) ++ wlc->stf->phytxant = PHY_TXC_OLD_ANT_1; ++ else ++ wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST; ++ } ++ ++ brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); ++} ++ ++int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force) ++{ ++ u8 txchain = (u8) int_val; ++ u8 txstreams; ++ uint i; ++ ++ if (wlc->stf->txchain == txchain) ++ return 0; ++ ++ if ((txchain & ~wlc->stf->hw_txchain) ++ || !(txchain & wlc->stf->hw_txchain)) ++ return -EINVAL; ++ ++ /* ++ * if nrate override is configured to be non-SISO STF mode, reject ++ * reducing txchain to 1 ++ */ ++ txstreams = (u8) hweight8(txchain); ++ if (txstreams > MAX_STREAMS_SUPPORTED) ++ return -EINVAL; ++ ++ wlc->stf->txchain = txchain; ++ wlc->stf->txstreams = txstreams; ++ brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx); ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); ++ wlc->stf->txant = ++ (wlc->stf->txstreams == 1) ? ANT_TX_FORCE_0 : ANT_TX_DEF; ++ _brcms_c_stf_phy_txant_upd(wlc); ++ ++ wlc_phy_stf_chain_set(wlc->band->pi, wlc->stf->txchain, ++ wlc->stf->rxchain); ++ ++ for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) ++ brcms_c_stf_txcore_set(wlc, (u8) i, txcore_default[i]); ++ ++ return 0; ++} ++ ++/* ++ * update wlc->stf->ss_opmode which represents the operational stf_ss mode ++ * we're using ++ */ ++int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band) ++{ ++ int ret_code = 0; ++ u8 prev_stf_ss; ++ u8 upd_stf_ss; ++ ++ prev_stf_ss = wlc->stf->ss_opmode; ++ ++ /* ++ * NOTE: opmode can only be SISO or CDD as STBC is decided on a ++ * per-packet basis ++ */ ++ if (BRCMS_STBC_CAP_PHY(wlc) && ++ wlc->stf->ss_algosel_auto ++ && (wlc->stf->ss_algo_channel != (u16) -1)) { ++ upd_stf_ss = (wlc->stf->txstreams == 1 || ++ isset(&wlc->stf->ss_algo_channel, ++ PHY_TXC1_MODE_SISO)) ? ++ PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD; ++ } else { ++ if (wlc->band != band) ++ return ret_code; ++ upd_stf_ss = (wlc->stf->txstreams == 1) ? ++ PHY_TXC1_MODE_SISO : band->band_stf_ss_mode; ++ } ++ if (prev_stf_ss != upd_stf_ss) { ++ wlc->stf->ss_opmode = upd_stf_ss; ++ brcms_b_band_stf_ss_set(wlc->hw, upd_stf_ss); ++ } ++ ++ return ret_code; ++} ++ ++int brcms_c_stf_attach(struct brcms_c_info *wlc) ++{ ++ wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO; ++ wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; ++ ++ if (BRCMS_ISNPHY(wlc->band) && ++ (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON)) ++ wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = ++ PHY_TXC1_MODE_CDD; ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); ++ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); ++ ++ brcms_c_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO); ++ wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF; ++ wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF; ++ ++ if (BRCMS_STBC_CAP_PHY(wlc)) { ++ wlc->stf->ss_algosel_auto = true; ++ /* Init the default value */ ++ wlc->stf->ss_algo_channel = (u16) -1; ++ } ++ return 0; ++} ++ ++void brcms_c_stf_detach(struct brcms_c_info *wlc) ++{ ++} ++ ++void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) ++{ ++ _brcms_c_stf_phy_txant_upd(wlc); ++} ++ ++void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc) ++{ ++ /* get available rx/tx chains */ ++ wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN); ++ wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN); ++ ++ /* these parameter are intended to be used for all PHY types */ ++ if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) { ++ if (BRCMS_ISNPHY(wlc->band)) ++ wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY; ++ else ++ wlc->stf->hw_txchain = TXCHAIN_DEF; ++ } ++ ++ wlc->stf->txchain = wlc->stf->hw_txchain; ++ wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain); ++ ++ if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) { ++ if (BRCMS_ISNPHY(wlc->band)) ++ wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY; ++ else ++ wlc->stf->hw_rxchain = RXCHAIN_DEF; ++ } ++ ++ wlc->stf->rxchain = wlc->stf->hw_rxchain; ++ wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain); ++ ++ /* initialize the txcore table */ ++ memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore)); ++ ++ /* default spatial_policy */ ++ wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION; ++ brcms_c_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION); ++} ++ ++static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, ++ u32 rspec) ++{ ++ u16 phytxant = wlc->stf->phytxant; ++ ++ if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO) ++ phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; ++ else if (wlc->stf->txant == ANT_TX_DEF) ++ phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; ++ phytxant &= PHY_TXC_ANT_MASK; ++ return phytxant; ++} ++ ++u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec) ++{ ++ return _brcms_c_stf_phytxchain_sel(wlc, rspec); ++} ++ ++u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec) ++{ ++ u16 phytxant = wlc->stf->phytxant; ++ u16 mask = PHY_TXC_ANT_MASK; ++ ++ /* for non-siso rates or default setting, use the available chains */ ++ if (BRCMS_ISNPHY(wlc->band)) { ++ phytxant = _brcms_c_stf_phytxchain_sel(wlc, rspec); ++ mask = PHY_TXC_HTANT_MASK; ++ } ++ phytxant |= phytxant & mask; ++ return phytxant; ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.h.orig 2011-11-09 13:46:58.286800121 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/stf.h 2011-11-09 13:47:17.045565604 -0500 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_STF_H_ ++#define _BRCM_STF_H_ ++ ++#include "types.h" ++ ++extern int brcms_c_stf_attach(struct brcms_c_info *wlc); ++extern void brcms_c_stf_detach(struct brcms_c_info *wlc); ++ ++extern void brcms_c_tempsense_upd(struct brcms_c_info *wlc); ++extern void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, ++ u16 *ss_algo_channel, ++ u16 chanspec); ++extern int brcms_c_stf_ss_update(struct brcms_c_info *wlc, ++ struct brcms_band *band); ++extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); ++extern int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, ++ bool force); ++extern bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val); ++extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); ++extern void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc); ++extern u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, ++ u32 rspec); ++extern u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, ++ u32 rspec); ++ ++#endif /* _BRCM_STF_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/types.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/types.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/types.h.orig 2011-11-09 13:46:58.286800121 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/types.h 2011-11-09 13:47:17.045565604 -0500 +@@ -0,0 +1,352 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_TYPES_H_ ++#define _BRCM_TYPES_H_ ++ ++#include ++#include ++ ++#define WL_CHAN_FREQ_RANGE_2G 0 ++#define WL_CHAN_FREQ_RANGE_5GL 1 ++#define WL_CHAN_FREQ_RANGE_5GM 2 ++#define WL_CHAN_FREQ_RANGE_5GH 3 ++ ++/* boardflags */ ++ ++/* Board has gpio 9 controlling the PA */ ++#define BFL_PACTRL 0x00000002 ++/* Not ok to power down the chip pll and oscillator */ ++#define BFL_NOPLLDOWN 0x00000020 ++/* Board supports the Front End Module */ ++#define BFL_FEM 0x00000800 ++/* Board has an external LNA in 2.4GHz band */ ++#define BFL_EXTLNA 0x00001000 ++/* Board has no PA */ ++#define BFL_NOPA 0x00010000 ++/* Power topology uses BUCKBOOST */ ++#define BFL_BUCKBOOST 0x00200000 ++/* Board has FEM and switch to share antenna w/ BT */ ++#define BFL_FEM_BT 0x00400000 ++/* Power topology doesn't use CBUCK */ ++#define BFL_NOCBUCK 0x00800000 ++/* Power topology uses PALDO */ ++#define BFL_PALDO 0x02000000 ++/* Board has an external LNA in 5GHz band */ ++#define BFL_EXTLNA_5GHz 0x10000000 ++ ++/* boardflags2 */ ++ ++/* Board has an external rxbb regulator */ ++#define BFL2_RXBB_INT_REG_DIS 0x00000001 ++/* Flag to implement alternative A-band PLL settings */ ++#define BFL2_APLL_WAR 0x00000002 ++/* Board permits enabling TX Power Control */ ++#define BFL2_TXPWRCTRL_EN 0x00000004 ++/* Board supports the 2X4 diversity switch */ ++#define BFL2_2X4_DIV 0x00000008 ++/* Board supports 5G band power gain */ ++#define BFL2_5G_PWRGAIN 0x00000010 ++/* Board overrides ASPM and Clkreq settings */ ++#define BFL2_PCIEWAR_OVR 0x00000020 ++#define BFL2_LEGACY 0x00000080 ++/* 4321mcm93 board uses Skyworks FEM */ ++#define BFL2_SKWRKFEM_BRD 0x00000100 ++/* Board has a WAR for clock-harmonic spurs */ ++#define BFL2_SPUR_WAR 0x00000200 ++/* Flag to narrow G-band PLL loop b/w */ ++#define BFL2_GPLL_WAR 0x00000400 ++/* Tx CCK pkts on Ant 0 only */ ++#define BFL2_SINGLEANT_CCK 0x00001000 ++/* WAR to reduce and avoid clock-harmonic spurs in 2G */ ++#define BFL2_2G_SPUR_WAR 0x00002000 ++/* Flag to widen G-band PLL loop b/w */ ++#define BFL2_GPLL_WAR2 0x00010000 ++#define BFL2_IPALVLSHIFT_3P3 0x00020000 ++/* Use internal envelope detector for TX IQCAL */ ++#define BFL2_INTERNDET_TXIQCAL 0x00040000 ++/* Keep the buffered Xtal output from radio "ON". Most drivers will turn it ++ * off without this flag to save power. */ ++#define BFL2_XTALBUFOUTEN 0x00080000 ++ ++/* ++ * board specific GPIO assignment, gpio 0-3 are also customer-configurable ++ * led ++ */ ++ ++/* bit 9 controls the PA on new 4306 boards */ ++#define BOARD_GPIO_PACTRL 0x200 ++#define BOARD_GPIO_12 0x1000 ++#define BOARD_GPIO_13 0x2000 ++ ++/* **** Core type/rev defaults **** */ ++#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27 ++ * also need to update wlc.h MAXCOREREV ++ */ ++ ++#define NCONF 0x000001ff /* Supported nphy revs: ++ * 0 4321a0 ++ * 1 4321a1 ++ * 2 4321b0/b1/c0/c1 ++ * 3 4322a0 ++ * 4 4322a1 ++ * 5 4716a0 ++ * 6 43222a0, 43224a0 ++ * 7 43226a0 ++ * 8 5357a0, 43236a0 ++ */ ++ ++#define LCNCONF 0x00000007 /* Supported lcnphy revs: ++ * 0 4313a0, 4336a0, 4330a0 ++ * 1 ++ * 2 4330a0 ++ */ ++ ++#define SSLPNCONF 0x0000000f /* Supported sslpnphy revs: ++ * 0 4329a0/k0 ++ * 1 4329b0/4329C0 ++ * 2 4319a0 ++ * 3 5356a0 ++ */ ++ ++/******************************************************************** ++ * Phy/Core Configuration. Defines macros to to check core phy/rev * ++ * compile-time configuration. Defines default core support. * ++ * ****************************************************************** ++ */ ++ ++/* Basic macros to check a configuration bitmask */ ++ ++#define CONF_HAS(config, val) ((config) & (1 << (val))) ++#define CONF_MSK(config, mask) ((config) & (mask)) ++#define MSK_RANGE(low, hi) ((1 << ((hi)+1)) - (1 << (low))) ++#define CONF_RANGE(config, low, hi) (CONF_MSK(config, MSK_RANGE(low, high))) ++ ++#define CONF_IS(config, val) ((config) == (1 << (val))) ++#define CONF_GE(config, val) ((config) & (0-(1 << (val)))) ++#define CONF_GT(config, val) ((config) & (0-2*(1 << (val)))) ++#define CONF_LT(config, val) ((config) & ((1 << (val))-1)) ++#define CONF_LE(config, val) ((config) & (2*(1 << (val))-1)) ++ ++/* Wrappers for some of the above, specific to config constants */ ++ ++#define NCONF_HAS(val) CONF_HAS(NCONF, val) ++#define NCONF_MSK(mask) CONF_MSK(NCONF, mask) ++#define NCONF_IS(val) CONF_IS(NCONF, val) ++#define NCONF_GE(val) CONF_GE(NCONF, val) ++#define NCONF_GT(val) CONF_GT(NCONF, val) ++#define NCONF_LT(val) CONF_LT(NCONF, val) ++#define NCONF_LE(val) CONF_LE(NCONF, val) ++ ++#define LCNCONF_HAS(val) CONF_HAS(LCNCONF, val) ++#define LCNCONF_MSK(mask) CONF_MSK(LCNCONF, mask) ++#define LCNCONF_IS(val) CONF_IS(LCNCONF, val) ++#define LCNCONF_GE(val) CONF_GE(LCNCONF, val) ++#define LCNCONF_GT(val) CONF_GT(LCNCONF, val) ++#define LCNCONF_LT(val) CONF_LT(LCNCONF, val) ++#define LCNCONF_LE(val) CONF_LE(LCNCONF, val) ++ ++#define D11CONF_HAS(val) CONF_HAS(D11CONF, val) ++#define D11CONF_MSK(mask) CONF_MSK(D11CONF, mask) ++#define D11CONF_IS(val) CONF_IS(D11CONF, val) ++#define D11CONF_GE(val) CONF_GE(D11CONF, val) ++#define D11CONF_GT(val) CONF_GT(D11CONF, val) ++#define D11CONF_LT(val) CONF_LT(D11CONF, val) ++#define D11CONF_LE(val) CONF_LE(D11CONF, val) ++ ++#define PHYCONF_HAS(val) CONF_HAS(PHYTYPE, val) ++#define PHYCONF_IS(val) CONF_IS(PHYTYPE, val) ++ ++#define NREV_IS(var, val) \ ++ (NCONF_HAS(val) && (NCONF_IS(val) || ((var) == (val)))) ++ ++#define NREV_GE(var, val) \ ++ (NCONF_GE(val) && (!NCONF_LT(val) || ((var) >= (val)))) ++ ++#define NREV_GT(var, val) \ ++ (NCONF_GT(val) && (!NCONF_LE(val) || ((var) > (val)))) ++ ++#define NREV_LT(var, val) \ ++ (NCONF_LT(val) && (!NCONF_GE(val) || ((var) < (val)))) ++ ++#define NREV_LE(var, val) \ ++ (NCONF_LE(val) && (!NCONF_GT(val) || ((var) <= (val)))) ++ ++#define LCNREV_IS(var, val) \ ++ (LCNCONF_HAS(val) && (LCNCONF_IS(val) || ((var) == (val)))) ++ ++#define LCNREV_GE(var, val) \ ++ (LCNCONF_GE(val) && (!LCNCONF_LT(val) || ((var) >= (val)))) ++ ++#define LCNREV_GT(var, val) \ ++ (LCNCONF_GT(val) && (!LCNCONF_LE(val) || ((var) > (val)))) ++ ++#define LCNREV_LT(var, val) \ ++ (LCNCONF_LT(val) && (!LCNCONF_GE(val) || ((var) < (val)))) ++ ++#define LCNREV_LE(var, val) \ ++ (LCNCONF_LE(val) && (!LCNCONF_GT(val) || ((var) <= (val)))) ++ ++#define D11REV_IS(var, val) \ ++ (D11CONF_HAS(val) && (D11CONF_IS(val) || ((var) == (val)))) ++ ++#define D11REV_GE(var, val) \ ++ (D11CONF_GE(val) && (!D11CONF_LT(val) || ((var) >= (val)))) ++ ++#define D11REV_GT(var, val) \ ++ (D11CONF_GT(val) && (!D11CONF_LE(val) || ((var) > (val)))) ++ ++#define D11REV_LT(var, val) \ ++ (D11CONF_LT(val) && (!D11CONF_GE(val) || ((var) < (val)))) ++ ++#define D11REV_LE(var, val) \ ++ (D11CONF_LE(val) && (!D11CONF_GT(val) || ((var) <= (val)))) ++ ++#define PHYTYPE_IS(var, val)\ ++ (PHYCONF_HAS(val) && (PHYCONF_IS(val) || ((var) == (val)))) ++ ++/* Set up PHYTYPE automatically: (depends on PHY_TYPE_X, from d11.h) */ ++ ++#define _PHYCONF_N (1 << PHY_TYPE_N) ++#define _PHYCONF_LCN (1 << PHY_TYPE_LCN) ++#define _PHYCONF_SSLPN (1 << PHY_TYPE_SSN) ++ ++#define PHYTYPE (_PHYCONF_N | _PHYCONF_LCN | _PHYCONF_SSLPN) ++ ++/* Utility macro to identify 802.11n (HT) capable PHYs */ ++#define PHYTYPE_11N_CAP(phytype) \ ++ (PHYTYPE_IS(phytype, PHY_TYPE_N) || \ ++ PHYTYPE_IS(phytype, PHY_TYPE_LCN) || \ ++ PHYTYPE_IS(phytype, PHY_TYPE_SSN)) ++ ++/* Last but not least: shorter wlc-specific var checks */ ++#define BRCMS_ISNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_N) ++#define BRCMS_ISLCNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_LCN) ++#define BRCMS_ISSSLPNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_SSN) ++ ++#define BRCMS_PHY_11N_CAP(band) PHYTYPE_11N_CAP((band)->phytype) ++ ++/********************************************************************** ++ * ------------- End of Core phy/rev configuration. ----------------- * ++ * ******************************************************************** ++ */ ++ ++#define BCMMSG(dev, fmt, args...) \ ++do { \ ++ if (brcm_msg_level & LOG_TRACE_VAL) \ ++ wiphy_err(dev, "%s: " fmt, __func__, ##args); \ ++} while (0) ++ ++/* ++ * Register access macros. ++ * ++ * These macro's take a pointer to the address to read as one of their ++ * arguments. The macro itself deduces the size of the IO transaction (u8, u16 ++ * or u32). Advantage of this approach in combination with using a struct to ++ * define the registers in a register block, is that access size and access ++ * location are defined in only one spot. This reduces the risk of the ++ * programmer trying to use an unsupported transaction size on a register. ++ * ++ */ ++ ++#define R_REG(r) \ ++ ({ \ ++ __typeof(*(r)) __osl_v; \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(u8): \ ++ __osl_v = readb((u8 __iomem *)(r)); \ ++ break; \ ++ case sizeof(u16): \ ++ __osl_v = readw((u16 __iomem *)(r)); \ ++ break; \ ++ case sizeof(u32): \ ++ __osl_v = readl((u32 __iomem *)(r)); \ ++ break; \ ++ } \ ++ __osl_v; \ ++ }) ++ ++#define W_REG(r, v) do { \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(u8): \ ++ writeb((u8)((v) & 0xFF), (u8 __iomem *)(r)); \ ++ break; \ ++ case sizeof(u16): \ ++ writew((u16)((v) & 0xFFFF), (u16 __iomem *)(r)); \ ++ break; \ ++ case sizeof(u32): \ ++ writel((u32)(v), (u32 __iomem *)(r)); \ ++ break; \ ++ } \ ++ } while (0) ++ ++#ifdef CONFIG_BCM47XX ++/* ++ * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder ++ * transactions. As a fix, a read after write is performed on certain places ++ * in the code. Older chips and the newer 5357 family don't require this fix. ++ */ ++#define W_REG_FLUSH(r, v) ({ W_REG((r), (v)); (void)R_REG(r); }) ++#else ++#define W_REG_FLUSH(r, v) W_REG((r), (v)) ++#endif /* CONFIG_BCM47XX */ ++ ++#define AND_REG(r, v) W_REG((r), R_REG(r) & (v)) ++#define OR_REG(r, v) W_REG((r), R_REG(r) | (v)) ++ ++#define SET_REG(r, mask, val) \ ++ W_REG((r), ((R_REG(r) & ~(mask)) | (val))) ++ ++/* multi-bool data type: set of bools, mbool is true if any is set */ ++ ++/* set one bool */ ++#define mboolset(mb, bit) ((mb) |= (bit)) ++/* clear one bool */ ++#define mboolclr(mb, bit) ((mb) &= ~(bit)) ++/* true if one bool is set */ ++#define mboolisset(mb, bit) (((mb) & (bit)) != 0) ++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) ++ ++#define CEIL(x, y) (((x) + ((y)-1)) / (y)) ++ ++/* forward declarations */ ++struct wiphy; ++struct ieee80211_sta; ++struct ieee80211_tx_queue_params; ++struct brcms_info; ++struct brcms_c_info; ++struct brcms_hardware; ++struct brcms_txq_info; ++struct brcms_band; ++struct dma_pub; ++struct si_pub; ++struct tx_status; ++struct d11rxhdr; ++struct txpwr_limits; ++ ++/* iovar structure */ ++struct brcmu_iovar { ++ const char *name; /* name for lookup and display */ ++ u16 varid; /* id for switch */ ++ u16 flags; /* driver-specific flag bits */ ++ u16 type; /* base type of argument */ ++ u16 minlen; /* min length for buffer vars */ ++}; ++ ++/* brcm_msg_level is a bit vector with defs in defs.h */ ++extern u32 brcm_msg_level; ++ ++#endif /* _BRCM_TYPES_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c.orig 2011-11-09 13:46:58.286800121 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c 2011-11-09 13:47:17.045565604 -0500 +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include "types.h" ++#include ++ ++enum { ++ D11UCODE_NAMETAG_START = 0, ++ D11LCN0BSINITVALS24, ++ D11LCN0INITVALS24, ++ D11LCN1BSINITVALS24, ++ D11LCN1INITVALS24, ++ D11LCN2BSINITVALS24, ++ D11LCN2INITVALS24, ++ D11N0ABSINITVALS16, ++ D11N0BSINITVALS16, ++ D11N0INITVALS16, ++ D11UCODE_OVERSIGHT16_MIMO, ++ D11UCODE_OVERSIGHT16_MIMOSZ, ++ D11UCODE_OVERSIGHT24_LCN, ++ D11UCODE_OVERSIGHT24_LCNSZ, ++ D11UCODE_OVERSIGHT_BOMMAJOR, ++ D11UCODE_OVERSIGHT_BOMMINOR ++}; ++ ++int brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode) ++{ ++ int rc; ++ ++ rc = brcms_check_firmwares(wl); ++ ++ rc = rc < 0 ? rc : ++ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0bsinitvals24, ++ D11LCN0BSINITVALS24); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0initvals24, ++ D11LCN0INITVALS24); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1bsinitvals24, ++ D11LCN1BSINITVALS24); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1initvals24, ++ D11LCN1INITVALS24); ++ rc = rc < 0 ? rc : ++ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2bsinitvals24, ++ D11LCN2BSINITVALS24); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2initvals24, ++ D11LCN2INITVALS24); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0absinitvals16, ++ D11N0ABSINITVALS16); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0bsinitvals16, ++ D11N0BSINITVALS16); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0initvals16, ++ D11N0INITVALS16); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_16_mimo, ++ D11UCODE_OVERSIGHT16_MIMO); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_16_mimosz, ++ D11UCODE_OVERSIGHT16_MIMOSZ); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_24_lcn, ++ D11UCODE_OVERSIGHT24_LCN); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_24_lcnsz, ++ D11UCODE_OVERSIGHT24_LCNSZ); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bommajor, ++ D11UCODE_OVERSIGHT_BOMMAJOR); ++ rc = rc < 0 ? ++ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bomminor, ++ D11UCODE_OVERSIGHT_BOMMINOR); ++ return rc; ++} ++ ++void brcms_ucode_data_free(struct brcms_ucode *ucode) ++{ ++ brcms_ucode_free_buf((void *)ucode->d11lcn0bsinitvals24); ++ brcms_ucode_free_buf((void *)ucode->d11lcn0initvals24); ++ brcms_ucode_free_buf((void *)ucode->d11lcn1bsinitvals24); ++ brcms_ucode_free_buf((void *)ucode->d11lcn1initvals24); ++ brcms_ucode_free_buf((void *)ucode->d11lcn2bsinitvals24); ++ brcms_ucode_free_buf((void *)ucode->d11lcn2initvals24); ++ brcms_ucode_free_buf((void *)ucode->d11n0absinitvals16); ++ brcms_ucode_free_buf((void *)ucode->d11n0bsinitvals16); ++ brcms_ucode_free_buf((void *)ucode->d11n0initvals16); ++ brcms_ucode_free_buf((void *)ucode->bcm43xx_16_mimo); ++ brcms_ucode_free_buf((void *)ucode->bcm43xx_24_lcn); ++ brcms_ucode_free_buf((void *)ucode->bcm43xx_bommajor); ++ brcms_ucode_free_buf((void *)ucode->bcm43xx_bomminor); ++} +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h.orig 2011-11-09 13:46:58.287800109 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h 2011-11-09 13:47:17.046565592 -0500 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#ifndef _BRCM_UCODE_H_ ++#define _BRCM_UCODE_H_ ++ ++#include "types.h" /* forward structure declarations */ ++ ++#define MIN_FW_SIZE 40000 /* minimum firmware file size in bytes */ ++#define MAX_FW_SIZE 150000 ++ ++#define UCODE_LOADER_API_VER 0 ++ ++struct d11init; ++ ++struct brcms_ucode { ++ struct d11init *d11lcn0bsinitvals24; ++ struct d11init *d11lcn0initvals24; ++ struct d11init *d11lcn1bsinitvals24; ++ struct d11init *d11lcn1initvals24; ++ struct d11init *d11lcn2bsinitvals24; ++ struct d11init *d11lcn2initvals24; ++ struct d11init *d11n0absinitvals16; ++ struct d11init *d11n0bsinitvals16; ++ struct d11init *d11n0initvals16; ++ __le32 *bcm43xx_16_mimo; ++ size_t bcm43xx_16_mimosz; ++ __le32 *bcm43xx_24_lcn; ++ size_t bcm43xx_24_lcnsz; ++ u32 *bcm43xx_bommajor; ++ u32 *bcm43xx_bomminor; ++}; ++ ++extern int ++brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode); ++ ++extern void brcms_ucode_data_free(struct brcms_ucode *ucode); ++ ++extern int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, ++ unsigned int idx); ++extern int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, ++ unsigned int idx); ++extern void brcms_ucode_free_buf(void *); ++extern int brcms_check_firmwares(struct brcms_info *wl); ++ ++#endif /* _BRCM_UCODE_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/Makefile.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/Makefile +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/Makefile.orig 2011-11-09 13:46:58.287800109 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/Makefile 2011-11-09 13:47:17.046565592 -0500 +@@ -0,0 +1,28 @@ ++# ++# Makefile fragment for Broadcom 802.11n Networking Device Driver Utilities ++# ++# Copyright (c) 2011 Broadcom Corporation ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# 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. ++ ++ccflags-y := \ ++ -Idrivers/net/wireless/brcm80211/brcmutil \ ++ -Idrivers/net/wireless/brcm80211/include ++ ++BRCMUTIL_OFILES := \ ++ utils.o ++ ++MODULEPFX := brcmutil ++ ++obj-$(CONFIG_BRCMUTIL) += $(MODULEPFX).o ++$(MODULEPFX)-objs = $(BRCMUTIL_OFILES) +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/utils.c.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/utils.c +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/utils.c.orig 2011-11-09 13:46:58.287800109 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/brcmutil/utils.c 2011-11-09 13:47:17.046565592 -0500 +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Broadcom Corporation"); ++MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities."); ++MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++struct sk_buff *brcmu_pkt_buf_get_skb(uint len) ++{ ++ struct sk_buff *skb; ++ ++ skb = dev_alloc_skb(len); ++ if (skb) { ++ skb_put(skb, len); ++ skb->priority = 0; ++ } ++ ++ return skb; ++} ++EXPORT_SYMBOL(brcmu_pkt_buf_get_skb); ++ ++/* Free the driver packet. Free the tag if present */ ++void brcmu_pkt_buf_free_skb(struct sk_buff *skb) ++{ ++ struct sk_buff *nskb; ++ int nest = 0; ++ ++ /* perversion: we use skb->next to chain multi-skb packets */ ++ while (skb) { ++ nskb = skb->next; ++ skb->next = NULL; ++ ++ if (skb->destructor) ++ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if ++ * destructor exists ++ */ ++ dev_kfree_skb_any(skb); ++ else ++ /* can free immediately (even in_irq()) if destructor ++ * does not exist ++ */ ++ dev_kfree_skb(skb); ++ ++ nest++; ++ skb = nskb; ++ } ++} ++EXPORT_SYMBOL(brcmu_pkt_buf_free_skb); ++ ++ ++/* copy a buffer into a pkt buffer chain */ ++uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len, ++ unsigned char *buf) ++{ ++ uint n, ret = 0; ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = p->next) { ++ if (offset < (uint) (p->len)) ++ break; ++ offset -= p->len; ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = p->next) { ++ n = min((uint) (p->len) - offset, (uint) len); ++ memcpy(p->data + offset, buf, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(brcmu_pktfrombuf); ++ ++/* return total length of buffer chain */ ++uint brcmu_pkttotlen(struct sk_buff *p) ++{ ++ uint total; ++ ++ total = 0; ++ for (; p; p = p->next) ++ total += p->len; ++ return total; ++} ++EXPORT_SYMBOL(brcmu_pkttotlen); ++ ++/* ++ * osl multiple-precedence packet queue ++ * hi_prec is always >= the number of the highest non-empty precedence ++ */ ++struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, ++ struct sk_buff *p) ++{ ++ struct pktq_prec *q; ++ ++ if (pktq_full(pq) || pktq_pfull(pq, prec)) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if (q->head) ++ q->tail->prev = p; ++ else ++ q->head = p; ++ ++ q->tail = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (u8) prec; ++ ++ return p; ++} ++EXPORT_SYMBOL(brcmu_pktq_penq); ++ ++struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, ++ struct sk_buff *p) ++{ ++ struct pktq_prec *q; ++ ++ if (pktq_full(pq) || pktq_pfull(pq, prec)) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == NULL) ++ q->tail = p; ++ ++ p->prev = q->head; ++ q->head = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (u8) prec; ++ ++ return p; ++} ++EXPORT_SYMBOL(brcmu_pktq_penq_head); ++ ++struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ struct sk_buff *p; ++ ++ q = &pq->q[prec]; ++ ++ p = q->head; ++ if (p == NULL) ++ return NULL; ++ ++ q->head = p->prev; ++ if (q->head == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ p->prev = NULL; ++ ++ return p; ++} ++EXPORT_SYMBOL(brcmu_pktq_pdeq); ++ ++struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ struct sk_buff *p, *prev; ++ ++ q = &pq->q[prec]; ++ ++ p = q->head; ++ if (p == NULL) ++ return NULL; ++ ++ for (prev = NULL; p != q->tail; p = p->prev) ++ prev = p; ++ ++ if (prev) ++ prev->prev = NULL; ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ return p; ++} ++EXPORT_SYMBOL(brcmu_pktq_pdeq_tail); ++ ++void ++brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, ++ bool (*fn)(struct sk_buff *, void *), void *arg) ++{ ++ struct pktq_prec *q; ++ struct sk_buff *p, *prev = NULL; ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ while (p) { ++ if (fn == NULL || (*fn) (p, arg)) { ++ bool head = (p == q->head); ++ if (head) ++ q->head = p->prev; ++ else ++ prev->prev = p->prev; ++ p->prev = NULL; ++ brcmu_pkt_buf_free_skb(p); ++ q->len--; ++ pq->len--; ++ p = (head ? q->head : prev->prev); ++ } else { ++ prev = p; ++ p = p->prev; ++ } ++ } ++ ++ if (q->head == NULL) ++ q->tail = NULL; ++} ++EXPORT_SYMBOL(brcmu_pktq_pflush); ++ ++void brcmu_pktq_flush(struct pktq *pq, bool dir, ++ bool (*fn)(struct sk_buff *, void *), void *arg) ++{ ++ int prec; ++ for (prec = 0; prec < pq->num_prec; prec++) ++ brcmu_pktq_pflush(pq, prec, dir, fn, arg); ++} ++EXPORT_SYMBOL(brcmu_pktq_flush); ++ ++void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len) ++{ ++ int prec; ++ ++ /* pq is variable size; only zero out what's requested */ ++ memset(pq, 0, ++ offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); ++ ++ pq->num_prec = (u16) num_prec; ++ ++ pq->max = (u16) max_len; ++ ++ for (prec = 0; prec < num_prec; prec++) ++ pq->q[prec].max = pq->max; ++} ++EXPORT_SYMBOL(brcmu_pktq_init); ++ ++struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return pq->q[prec].tail; ++} ++EXPORT_SYMBOL(brcmu_pktq_peek_tail); ++ ++/* Return sum of lengths of a specific set of precedences */ ++int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp) ++{ ++ int prec, len; ++ ++ len = 0; ++ ++ for (prec = 0; prec <= pq->hi_prec; prec++) ++ if (prec_bmp & (1 << prec)) ++ len += pq->q[prec].len; ++ ++ return len; ++} ++EXPORT_SYMBOL(brcmu_pktq_mlen); ++ ++/* Priority dequeue from a specific set of precedences */ ++struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, ++ int *prec_out) ++{ ++ struct pktq_prec *q; ++ struct sk_buff *p; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) ++ if (prec-- == 0) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ p = q->head; ++ if (p == NULL) ++ return NULL; ++ ++ q->head = p->prev; ++ if (q->head == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ pq->len--; ++ ++ p->prev = NULL; ++ ++ return p; ++} ++EXPORT_SYMBOL(brcmu_pktq_mdeq); ++ ++#if defined(BCMDBG) ++/* pretty hex print a pkt buffer chain */ ++void brcmu_prpkt(const char *msg, struct sk_buff *p0) ++{ ++ struct sk_buff *p; ++ ++ if (msg && (msg[0] != '\0')) ++ printk(KERN_DEBUG "%s:\n", msg); ++ ++ for (p = p0; p; p = p->next) ++ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len); ++} ++EXPORT_SYMBOL(brcmu_prpkt); ++#endif /* defined(BCMDBG) */ ++ ++#if defined(BCMDBG) ++/* ++ * print bytes formatted as hex to a string. return the resulting ++ * string length ++ */ ++int brcmu_format_hex(char *str, const void *bytes, int len) ++{ ++ int i; ++ char *p = str; ++ const u8 *src = (const u8 *)bytes; ++ ++ for (i = 0; i < len; i++) { ++ p += snprintf(p, 3, "%02X", *src); ++ src++; ++ } ++ return (int)(p - str); ++} ++EXPORT_SYMBOL(brcmu_format_hex); ++#endif /* defined(BCMDBG) */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h.orig 2011-11-09 13:46:58.287800109 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h 2011-11-09 13:47:17.046565592 -0500 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_HW_IDS_H_ ++#define _BRCM_HW_IDS_H_ ++ ++#define BCM4325_D11DUAL_ID 0x431b ++#define BCM4325_D11G_ID 0x431c ++#define BCM4325_D11A_ID 0x431d ++ ++#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ ++#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ ++#define BCM4329_D11NDUAL_ID 0x432e ++ ++#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ ++#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ ++#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ ++ ++#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ ++#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */ ++ ++#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ ++ ++#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ ++#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ ++ ++#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ ++ ++/* Chip IDs */ ++#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ ++#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ ++ ++#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ ++#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ ++#define BCM43421_CHIP_ID 43421 /* 43421 chipcommon chipid */ ++#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ ++#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ ++#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ ++#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ ++#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */ ++#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ ++#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ ++#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ ++#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ ++ ++#endif /* _BRCM_HW_IDS_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_utils.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_utils.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_utils.h.orig 2011-11-09 13:46:58.288800096 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_utils.h 2011-11-09 13:47:17.047565580 -0500 +@@ -0,0 +1,195 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCMU_UTILS_H_ ++#define _BRCMU_UTILS_H_ ++ ++#include ++ ++/* ++ * Spin at most 'us' microseconds while 'exp' is true. ++ * Caller should explicitly test 'exp' when this completes ++ * and take appropriate error action if 'exp' is still true. ++ */ ++#define SPINWAIT(exp, us) { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) {\ ++ udelay(10); \ ++ countdown -= 10; \ ++ } \ ++} ++ ++/* osl multi-precedence packet queue */ ++#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ ++#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ ++ ++#define BCME_STRLEN 64 /* Max string length for BCM errors */ ++ ++/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ ++#define PKTBUFSZ 2048 ++ ++#ifndef setbit ++#ifndef NBBY /* the BSD family defines NBBY */ ++#define NBBY 8 /* 8 bits per byte */ ++#endif /* #ifndef NBBY */ ++#define setbit(a, i) (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY)) ++#define clrbit(a, i) (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) ++#define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) ++#define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) ++#endif /* setbit */ ++ ++#define NBITS(type) (sizeof(type) * 8) ++#define NBITVAL(nbits) (1 << (nbits)) ++#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) ++#define NBITMASK(nbits) MAXBITVAL(nbits) ++#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) ++ ++/* crc defines */ ++#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ ++#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ ++ ++/* 18-bytes of Ethernet address buffer length */ ++#define ETHER_ADDR_STR_LEN 18 ++ ++struct pktq_prec { ++ struct sk_buff *head; /* first packet to dequeue */ ++ struct sk_buff *tail; /* last packet to dequeue */ ++ u16 len; /* number of queued packets */ ++ u16 max; /* maximum number of queued packets */ ++}; ++ ++/* multi-priority pkt queue */ ++struct pktq { ++ u16 num_prec; /* number of precedences in use */ ++ u16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ ++ u16 max; /* total max packets */ ++ u16 len; /* total number of packets */ ++ /* ++ * q array must be last since # of elements can be either ++ * PKTQ_MAX_PREC or 1 ++ */ ++ struct pktq_prec q[PKTQ_MAX_PREC]; ++}; ++ ++/* operations on a specific precedence in packet queue */ ++ ++static inline int pktq_plen(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].len; ++} ++ ++static inline int pktq_pavail(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].max - pq->q[prec].len; ++} ++ ++static inline bool pktq_pfull(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].len >= pq->q[prec].max; ++} ++ ++static inline bool pktq_pempty(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].len == 0; ++} ++ ++static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].head; ++} ++ ++static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec) ++{ ++ return pq->q[prec].tail; ++} ++ ++extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, ++ struct sk_buff *p); ++extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, ++ struct sk_buff *p); ++extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec); ++extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec); ++ ++/* packet primitives */ ++extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len); ++extern void brcmu_pkt_buf_free_skb(struct sk_buff *skb); ++ ++/* Empty the queue at particular precedence level */ ++/* callback function fn(pkt, arg) returns true if pkt belongs to if */ ++extern void brcmu_pktq_pflush(struct pktq *pq, int prec, ++ bool dir, bool (*fn)(struct sk_buff *, void *), void *arg); ++ ++/* operations on a set of precedences in packet queue */ ++ ++extern int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp); ++extern struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, ++ int *prec_out); ++ ++/* operations on packet queue as a whole */ ++ ++static inline int pktq_len(struct pktq *pq) ++{ ++ return (int)pq->len; ++} ++ ++static inline int pktq_max(struct pktq *pq) ++{ ++ return (int)pq->max; ++} ++ ++static inline int pktq_avail(struct pktq *pq) ++{ ++ return (int)(pq->max - pq->len); ++} ++ ++static inline bool pktq_full(struct pktq *pq) ++{ ++ return pq->len >= pq->max; ++} ++ ++static inline bool pktq_empty(struct pktq *pq) ++{ ++ return pq->len == 0; ++} ++ ++extern void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len); ++/* prec_out may be NULL if caller is not interested in return value */ ++extern struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out); ++extern void brcmu_pktq_flush(struct pktq *pq, bool dir, ++ bool (*fn)(struct sk_buff *, void *), void *arg); ++ ++/* externs */ ++/* packet */ ++extern uint brcmu_pktfrombuf(struct sk_buff *p, ++ uint offset, int len, unsigned char *buf); ++extern uint brcmu_pkttotlen(struct sk_buff *p); ++ ++/* ip address */ ++struct ipv4_addr; ++ ++#ifdef BCMDBG ++extern void brcmu_prpkt(const char *msg, struct sk_buff *p0); ++#else ++#define brcmu_prpkt(a, b) ++#endif /* BCMDBG */ ++ ++/* externs */ ++/* format/print */ ++#if defined(BCMDBG) ++extern int brcmu_format_hex(char *str, const void *bytes, int len); ++#endif ++ ++#endif /* _BRCMU_UTILS_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_wifi.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_wifi.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_wifi.h.orig 2011-11-09 13:46:58.288800096 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/brcmu_wifi.h 2011-11-09 13:47:17.047565580 -0500 +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCMU_WIFI_H_ ++#define _BRCMU_WIFI_H_ ++ ++#include /* for ETH_ALEN */ ++#include /* for WLAN_PMKID_LEN */ ++ ++/* ++ * A chanspec (u16) holds the channel number, band, bandwidth and control ++ * sideband ++ */ ++ ++/* channel defines */ ++#define CH_UPPER_SB 0x01 ++#define CH_LOWER_SB 0x02 ++#define CH_EWA_VALID 0x04 ++#define CH_20MHZ_APART 4 ++#define CH_10MHZ_APART 2 ++#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ ++#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */ ++ ++/* bandstate array indices */ ++#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */ ++#define BAND_5G_INDEX 1 /* wlc->bandstate[x] index */ ++ ++/* ++ * max # supported channels. The max channel no is 216, this is that + 1 ++ * rounded up to a multiple of NBBY (8). DO NOT MAKE it > 255: channels are ++ * u8's all over ++*/ ++#define MAXCHANNEL 224 ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_CHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_CHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_CHANSPEC_BW_MASK 0x0C00 ++#define WL_CHANSPEC_BW_SHIFT 10 ++#define WL_CHANSPEC_BW_10 0x0400 ++#define WL_CHANSPEC_BW_20 0x0800 ++#define WL_CHANSPEC_BW_40 0x0C00 ++ ++#define WL_CHANSPEC_BAND_MASK 0xf000 ++#define WL_CHANSPEC_BAND_SHIFT 12 ++#define WL_CHANSPEC_BAND_5G 0x1000 ++#define WL_CHANSPEC_BAND_2G 0x2000 ++#define INVCHANSPEC 255 ++ ++/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */ ++#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ ++#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ ++#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ ++ ++#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++ ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#define CHSPEC_IS10(chspec) \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++ ++#define CHSPEC_IS20(chspec) \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) ++ ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++ ++#define CHSPEC_IS5G(chspec) \ ++ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) ++ ++#define CHSPEC_IS2G(chspec) \ ++ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) ++ ++#define CHSPEC_SB_NONE(chspec) \ ++ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) ++ ++#define CHSPEC_SB_UPPER(chspec) \ ++ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) ++ ++#define CHSPEC_SB_LOWER(chspec) \ ++ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) ++ ++#define CHSPEC_CTL_CHAN(chspec) \ ++ ((CHSPEC_SB_LOWER(chspec)) ? \ ++ (lower_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ ++ (upper_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK)))) ++ ++#define CHSPEC2BAND(chspec) (CHSPEC_IS5G(chspec) ? BRCM_BAND_5G : BRCM_BAND_2G) ++ ++#define CHANSPEC_STR_LEN 8 ++ ++static inline int lower_20_sb(int channel) ++{ ++ return channel > CH_10MHZ_APART ? (channel - CH_10MHZ_APART) : 0; ++} ++ ++static inline int upper_20_sb(int channel) ++{ ++ return (channel < (MAXCHANNEL - CH_10MHZ_APART)) ? ++ channel + CH_10MHZ_APART : 0; ++} ++ ++static inline int chspec_bandunit(u16 chspec) ++{ ++ return CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX; ++} ++ ++static inline u16 ch20mhz_chspec(int channel) ++{ ++ u16 rc = channel <= CH_MAX_2G_CHANNEL ? ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G; ++ ++ return (u16)((u16)channel | WL_CHANSPEC_BW_20 | ++ WL_CHANSPEC_CTL_SB_NONE | rc); ++} ++ ++static inline int next_20mhz_chan(int channel) ++{ ++ return channel < (MAXCHANNEL - CH_20MHZ_APART) ? ++ channel + CH_20MHZ_APART : 0; ++} ++ ++/* defined rate in 500kbps */ ++#define BRCM_MAXRATE 108 /* in 500kbps units */ ++#define BRCM_RATE_1M 2 /* in 500kbps units */ ++#define BRCM_RATE_2M 4 /* in 500kbps units */ ++#define BRCM_RATE_5M5 11 /* in 500kbps units */ ++#define BRCM_RATE_11M 22 /* in 500kbps units */ ++#define BRCM_RATE_6M 12 /* in 500kbps units */ ++#define BRCM_RATE_9M 18 /* in 500kbps units */ ++#define BRCM_RATE_12M 24 /* in 500kbps units */ ++#define BRCM_RATE_18M 36 /* in 500kbps units */ ++#define BRCM_RATE_24M 48 /* in 500kbps units */ ++#define BRCM_RATE_36M 72 /* in 500kbps units */ ++#define BRCM_RATE_48M 96 /* in 500kbps units */ ++#define BRCM_RATE_54M 108 /* in 500kbps units */ ++ ++#define BRCM_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ ++ ++#define MCSSET_LEN 16 ++ ++static inline bool ac_bitmap_tst(u8 bitmap, int prec) ++{ ++ return (bitmap & (1 << (prec))) != 0; ++} ++ ++/* Enumerate crypto algorithms */ ++#define CRYPTO_ALGO_OFF 0 ++#define CRYPTO_ALGO_WEP1 1 ++#define CRYPTO_ALGO_TKIP 2 ++#define CRYPTO_ALGO_WEP128 3 ++#define CRYPTO_ALGO_AES_CCM 4 ++#define CRYPTO_ALGO_AES_RESERVED1 5 ++#define CRYPTO_ALGO_AES_RESERVED2 6 ++#define CRYPTO_ALGO_NALG 7 ++ ++/* wireless security bitvec */ ++ ++#define WEP_ENABLED 0x0001 ++#define TKIP_ENABLED 0x0002 ++#define AES_ENABLED 0x0004 ++#define WSEC_SWFLAG 0x0008 ++/* to go into transition mode without setting wep */ ++#define SES_OW_ENABLED 0x0040 ++ ++/* WPA authentication mode bitvec */ ++#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ ++#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ ++#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ ++#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ ++#define WPA_AUTH_RESERVED1 0x0008 ++#define WPA_AUTH_RESERVED2 0x0010 ++ ++#define WPA2_AUTH_RESERVED1 0x0020 ++#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ ++#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ ++#define WPA2_AUTH_RESERVED3 0x0200 ++#define WPA2_AUTH_RESERVED4 0x0400 ++#define WPA2_AUTH_RESERVED5 0x0800 ++ ++/* pmkid */ ++#define MAXPMKID 16 ++ ++#define DOT11_DEFAULT_RTS_LEN 2347 ++#define DOT11_DEFAULT_FRAG_LEN 2346 ++ ++#define DOT11_ICV_AES_LEN 8 ++#define DOT11_QOS_LEN 2 ++#define DOT11_IV_MAX_LEN 8 ++#define DOT11_A4_HDR_LEN 30 ++ ++#define HT_CAP_RX_STBC_NO 0x0 ++#define HT_CAP_RX_STBC_ONE_STREAM 0x1 ++ ++struct pmkid { ++ u8 BSSID[ETH_ALEN]; ++ u8 PMKID[WLAN_PMKID_LEN]; ++}; ++ ++struct pmkid_list { ++ __le32 npmkid; ++ struct pmkid pmkid[1]; ++}; ++ ++struct pmkid_cand { ++ u8 BSSID[ETH_ALEN]; ++ u8 preauth; ++}; ++ ++struct pmkid_cand_list { ++ u32 npmkid_cand; ++ struct pmkid_cand pmkid_cand[1]; ++}; ++ ++#endif /* _BRCMU_WIFI_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/chipcommon.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/chipcommon.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/chipcommon.h.orig 2011-11-09 13:46:58.288800096 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/chipcommon.h 2011-11-09 13:47:17.047565580 -0500 +@@ -0,0 +1,284 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _SBCHIPC_H ++#define _SBCHIPC_H ++ ++#include "defs.h" /* for PAD macro */ ++ ++struct chipcregs { ++ u32 chipid; /* 0x0 */ ++ u32 capabilities; ++ u32 corecontrol; /* corerev >= 1 */ ++ u32 bist; ++ ++ /* OTP */ ++ u32 otpstatus; /* 0x10, corerev >= 10 */ ++ u32 otpcontrol; ++ u32 otpprog; ++ u32 otplayout; /* corerev >= 23 */ ++ ++ /* Interrupt control */ ++ u32 intstatus; /* 0x20 */ ++ u32 intmask; ++ ++ /* Chip specific regs */ ++ u32 chipcontrol; /* 0x28, rev >= 11 */ ++ u32 chipstatus; /* 0x2c, rev >= 11 */ ++ ++ /* Jtag Master */ ++ u32 jtagcmd; /* 0x30, rev >= 10 */ ++ u32 jtagir; ++ u32 jtagdr; ++ u32 jtagctrl; ++ ++ /* serial flash interface registers */ ++ u32 flashcontrol; /* 0x40 */ ++ u32 flashaddress; ++ u32 flashdata; ++ u32 PAD[1]; ++ ++ /* Silicon backplane configuration broadcast control */ ++ u32 broadcastaddress; /* 0x50 */ ++ u32 broadcastdata; ++ ++ /* gpio - cleared only by power-on-reset */ ++ u32 gpiopullup; /* 0x58, corerev >= 20 */ ++ u32 gpiopulldown; /* 0x5c, corerev >= 20 */ ++ u32 gpioin; /* 0x60 */ ++ u32 gpioout; /* 0x64 */ ++ u32 gpioouten; /* 0x68 */ ++ u32 gpiocontrol; /* 0x6C */ ++ u32 gpiointpolarity; /* 0x70 */ ++ u32 gpiointmask; /* 0x74 */ ++ ++ /* GPIO events corerev >= 11 */ ++ u32 gpioevent; ++ u32 gpioeventintmask; ++ ++ /* Watchdog timer */ ++ u32 watchdog; /* 0x80 */ ++ ++ /* GPIO events corerev >= 11 */ ++ u32 gpioeventintpolarity; ++ ++ /* GPIO based LED powersave registers corerev >= 16 */ ++ u32 gpiotimerval; /* 0x88 */ ++ u32 gpiotimeroutmask; ++ ++ /* clock control */ ++ u32 clockcontrol_n; /* 0x90 */ ++ u32 clockcontrol_sb; /* aka m0 */ ++ u32 clockcontrol_pci; /* aka m1 */ ++ u32 clockcontrol_m2; /* mii/uart/mipsref */ ++ u32 clockcontrol_m3; /* cpu */ ++ u32 clkdiv; /* corerev >= 3 */ ++ u32 gpiodebugsel; /* corerev >= 28 */ ++ u32 capabilities_ext; /* 0xac */ ++ ++ /* pll delay registers (corerev >= 4) */ ++ u32 pll_on_delay; /* 0xb0 */ ++ u32 fref_sel_delay; ++ u32 slow_clk_ctl; /* 5 < corerev < 10 */ ++ u32 PAD; ++ ++ /* Instaclock registers (corerev >= 10) */ ++ u32 system_clk_ctl; /* 0xc0 */ ++ u32 clkstatestretch; ++ u32 PAD[2]; ++ ++ /* Indirect backplane access (corerev >= 22) */ ++ u32 bp_addrlow; /* 0xd0 */ ++ u32 bp_addrhigh; ++ u32 bp_data; ++ u32 PAD; ++ u32 bp_indaccess; ++ u32 PAD[3]; ++ ++ /* More clock dividers (corerev >= 32) */ ++ u32 clkdiv2; ++ u32 PAD[2]; ++ ++ /* In AI chips, pointer to erom */ ++ u32 eromptr; /* 0xfc */ ++ ++ /* ExtBus control registers (corerev >= 3) */ ++ u32 pcmcia_config; /* 0x100 */ ++ u32 pcmcia_memwait; ++ u32 pcmcia_attrwait; ++ u32 pcmcia_iowait; ++ u32 ide_config; ++ u32 ide_memwait; ++ u32 ide_attrwait; ++ u32 ide_iowait; ++ u32 prog_config; ++ u32 prog_waitcount; ++ u32 flash_config; ++ u32 flash_waitcount; ++ u32 SECI_config; /* 0x130 SECI configuration */ ++ u32 PAD[3]; ++ ++ /* Enhanced Coexistence Interface (ECI) registers (corerev >= 21) */ ++ u32 eci_output; /* 0x140 */ ++ u32 eci_control; ++ u32 eci_inputlo; ++ u32 eci_inputmi; ++ u32 eci_inputhi; ++ u32 eci_inputintpolaritylo; ++ u32 eci_inputintpolaritymi; ++ u32 eci_inputintpolarityhi; ++ u32 eci_intmasklo; ++ u32 eci_intmaskmi; ++ u32 eci_intmaskhi; ++ u32 eci_eventlo; ++ u32 eci_eventmi; ++ u32 eci_eventhi; ++ u32 eci_eventmasklo; ++ u32 eci_eventmaskmi; ++ u32 eci_eventmaskhi; ++ u32 PAD[3]; ++ ++ /* SROM interface (corerev >= 32) */ ++ u32 sromcontrol; /* 0x190 */ ++ u32 sromaddress; ++ u32 sromdata; ++ u32 PAD[17]; ++ ++ /* Clock control and hardware workarounds (corerev >= 20) */ ++ u32 clk_ctl_st; /* 0x1e0 */ ++ u32 hw_war; ++ u32 PAD[70]; ++ ++ /* UARTs */ ++ u8 uart0data; /* 0x300 */ ++ u8 uart0imr; ++ u8 uart0fcr; ++ u8 uart0lcr; ++ u8 uart0mcr; ++ u8 uart0lsr; ++ u8 uart0msr; ++ u8 uart0scratch; ++ u8 PAD[248]; /* corerev >= 1 */ ++ ++ u8 uart1data; /* 0x400 */ ++ u8 uart1imr; ++ u8 uart1fcr; ++ u8 uart1lcr; ++ u8 uart1mcr; ++ u8 uart1lsr; ++ u8 uart1msr; ++ u8 uart1scratch; ++ u32 PAD[126]; ++ ++ /* PMU registers (corerev >= 20) */ ++ u32 pmucontrol; /* 0x600 */ ++ u32 pmucapabilities; ++ u32 pmustatus; ++ u32 res_state; ++ u32 res_pending; ++ u32 pmutimer; ++ u32 min_res_mask; ++ u32 max_res_mask; ++ u32 res_table_sel; ++ u32 res_dep_mask; ++ u32 res_updn_timer; ++ u32 res_timer; ++ u32 clkstretch; ++ u32 pmuwatchdog; ++ u32 gpiosel; /* 0x638, rev >= 1 */ ++ u32 gpioenable; /* 0x63c, rev >= 1 */ ++ u32 res_req_timer_sel; ++ u32 res_req_timer; ++ u32 res_req_mask; ++ u32 PAD; ++ u32 chipcontrol_addr; /* 0x650 */ ++ u32 chipcontrol_data; /* 0x654 */ ++ u32 regcontrol_addr; ++ u32 regcontrol_data; ++ u32 pllcontrol_addr; ++ u32 pllcontrol_data; ++ u32 pmustrapopt; /* 0x668, corerev >= 28 */ ++ u32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ ++ u32 PAD[100]; ++ u16 sromotp[768]; ++}; ++ ++/* chipid */ ++#define CID_ID_MASK 0x0000ffff /* Chip Id mask */ ++#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */ ++#define CID_REV_SHIFT 16 /* Chip Revision shift */ ++#define CID_PKG_MASK 0x00f00000 /* Package Option mask */ ++#define CID_PKG_SHIFT 20 /* Package Option shift */ ++#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */ ++#define CID_CC_SHIFT 24 ++#define CID_TYPE_MASK 0xf0000000 /* Chip Type */ ++#define CID_TYPE_SHIFT 28 ++ ++/* capabilities */ ++#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */ ++#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ ++#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */ ++/* UARTs are driven by internal divided clock */ ++#define CC_CAP_UINTCLK 0x00000008 ++#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ ++#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ ++#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */ ++#define CC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */ ++#define CC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */ ++#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ ++#define CC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ ++#define CC_CAP_PWR_CTL 0x00040000 /* Power control */ ++#define CC_CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */ ++#define CC_CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */ ++#define CC_CAP_OTPSIZE_BASE 5 /* OTP Size base */ ++#define CC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ ++#define CC_CAP_ROM 0x00800000 /* Internal boot rom active */ ++#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ ++#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ ++#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ ++/* Nand flash present, rev >= 35 */ ++#define CC_CAP_NFLASH 0x80000000 ++ ++#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ ++/* GSIO (spi/i2c) present, rev >= 37 */ ++#define CC_CAP2_GSIO 0x00000002 ++ ++/* pmucapabilities */ ++#define PCAP_REV_MASK 0x000000ff ++#define PCAP_RC_MASK 0x00001f00 ++#define PCAP_RC_SHIFT 8 ++#define PCAP_TC_MASK 0x0001e000 ++#define PCAP_TC_SHIFT 13 ++#define PCAP_PC_MASK 0x001e0000 ++#define PCAP_PC_SHIFT 17 ++#define PCAP_VC_MASK 0x01e00000 ++#define PCAP_VC_SHIFT 21 ++#define PCAP_CC_MASK 0x1e000000 ++#define PCAP_CC_SHIFT 25 ++#define PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */ ++#define PCAP5_PC_SHIFT 17 ++#define PCAP5_VC_MASK 0x07c00000 ++#define PCAP5_VC_SHIFT 22 ++#define PCAP5_CC_MASK 0xf8000000 ++#define PCAP5_CC_SHIFT 27 ++ ++/* ++* Maximum delay for the PMU state transition in us. ++* This is an upper bound intended for spinwaits etc. ++*/ ++#define PMU_MAX_TRANSITION_DLY 15000 ++ ++#endif /* _SBCHIPC_H */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/defs.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/defs.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/defs.h.orig 2011-11-09 13:46:58.288800096 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/defs.h 2011-11-09 13:47:17.047565580 -0500 +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_DEFS_H_ ++#define _BRCM_DEFS_H_ ++ ++#include ++ ++#define SI_BUS 0 ++#define PCI_BUS 1 ++#define PCMCIA_BUS 2 ++#define SDIO_BUS 3 ++#define JTAG_BUS 4 ++#define USB_BUS 5 ++#define SPI_BUS 6 ++ ++#define OFF 0 ++#define ON 1 /* ON = 1 */ ++#define AUTO (-1) /* Auto = -1 */ ++ ++/* ++ * Priority definitions according 802.1D ++ */ ++#define PRIO_8021D_NONE 2 ++#define PRIO_8021D_BK 1 ++#define PRIO_8021D_BE 0 ++#define PRIO_8021D_EE 3 ++#define PRIO_8021D_CL 4 ++#define PRIO_8021D_VI 5 ++#define PRIO_8021D_VO 6 ++#define PRIO_8021D_NC 7 ++ ++#define MAXPRIO 7 ++#define NUMPRIO (MAXPRIO + 1) ++ ++#define WL_NUMRATES 16 /* max # of rates in a rateset */ ++ ++#define BRCM_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ ++ ++#define BRCM_SET_CHANNEL 30 ++#define BRCM_SET_SRL 32 ++#define BRCM_SET_LRL 34 ++#define BRCM_SET_BCNPRD 76 ++ ++#define BRCM_GET_CURR_RATESET 114 /* current rateset */ ++#define BRCM_GET_PHYLIST 180 ++ ++/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ ++ ++#define WL_RADIO_SW_DISABLE (1<<0) ++#define WL_RADIO_HW_DISABLE (1<<1) ++#define WL_RADIO_MPC_DISABLE (1<<2) ++/* some countries don't support any channel */ ++#define WL_RADIO_COUNTRY_DISABLE (1<<3) ++ ++/* Override bit for SET_TXPWR. if set, ignore other level limits */ ++#define WL_TXPWR_OVERRIDE (1U<<31) ++ ++/* band types */ ++#define BRCM_BAND_AUTO 0 /* auto-select */ ++#define BRCM_BAND_5G 1 /* 5 Ghz */ ++#define BRCM_BAND_2G 2 /* 2.4 Ghz */ ++#define BRCM_BAND_ALL 3 /* all bands */ ++ ++/* Values for PM */ ++#define PM_OFF 0 ++#define PM_MAX 1 ++ ++/* Message levels */ ++#define LOG_ERROR_VAL 0x00000001 ++#define LOG_TRACE_VAL 0x00000002 ++ ++#define PM_OFF 0 ++#define PM_MAX 1 ++#define PM_FAST 2 ++ ++/* ++ * Sonics Configuration Space Registers. ++ */ ++ ++/* core sbconfig regs are top 256bytes of regs */ ++#define SBCONFIGOFF 0xf00 ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++#endif /* _BRCM_DEFS_H_ */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/soc.h.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/soc.h +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/soc.h.orig 2011-11-09 13:46:58.288800096 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/include/soc.h 2011-11-09 13:47:17.048565567 -0500 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2010 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _BRCM_SOC_H ++#define _BRCM_SOC_H ++ ++#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ ++ ++/* core codes */ ++#define NODEV_CORE_ID 0x700 /* Invalid coreid */ ++#define CC_CORE_ID 0x800 /* chipcommon core */ ++#define ILINE20_CORE_ID 0x801 /* iline20 core */ ++#define SRAM_CORE_ID 0x802 /* sram core */ ++#define SDRAM_CORE_ID 0x803 /* sdram core */ ++#define PCI_CORE_ID 0x804 /* pci core */ ++#define MIPS_CORE_ID 0x805 /* mips core */ ++#define ENET_CORE_ID 0x806 /* enet mac core */ ++#define CODEC_CORE_ID 0x807 /* v90 codec core */ ++#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ ++#define ADSL_CORE_ID 0x809 /* ADSL core */ ++#define ILINE100_CORE_ID 0x80a /* iline100 core */ ++#define IPSEC_CORE_ID 0x80b /* ipsec core */ ++#define UTOPIA_CORE_ID 0x80c /* utopia core */ ++#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ ++#define SOCRAM_CORE_ID 0x80e /* internal memory core */ ++#define MEMC_CORE_ID 0x80f /* memc sdram core */ ++#define OFDM_CORE_ID 0x810 /* OFDM phy core */ ++#define EXTIF_CORE_ID 0x811 /* external interface core */ ++#define D11_CORE_ID 0x812 /* 802.11 MAC core */ ++#define APHY_CORE_ID 0x813 /* 802.11a phy core */ ++#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ ++#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ ++#define MIPS33_CORE_ID 0x816 /* mips3302 core */ ++#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ ++#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ ++#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ ++#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ ++#define SDIOH_CORE_ID 0x81b /* sdio host core */ ++#define ROBO_CORE_ID 0x81c /* roboswitch core */ ++#define ATA100_CORE_ID 0x81d /* parallel ATA core */ ++#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ ++#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ ++#define PCIE_CORE_ID 0x820 /* pci express core */ ++#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ ++#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ ++#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ ++#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ ++#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ ++#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ ++#define PMU_CORE_ID 0x827 /* PMU core */ ++#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ ++#define SDIOD_CORE_ID 0x829 /* SDIO device core */ ++#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ ++#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ ++#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ ++#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ ++#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ ++#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ ++#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ ++#define SC_CORE_ID 0x831 /* shared common core */ ++#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ ++#define SPIH_CORE_ID 0x833 /* SPI host core */ ++#define I2S_CORE_ID 0x834 /* I2S core */ ++#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ ++#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ ++#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ ++/* Default component, in ai chips it maps all unused address ranges */ ++#define DEF_AI_COMP 0xfff ++ ++/* Common core control flags */ ++#define SICF_BIST_EN 0x8000 ++#define SICF_PME_EN 0x4000 ++#define SICF_CORE_BITS 0x3ffc ++#define SICF_FGC 0x0002 ++#define SICF_CLOCK_EN 0x0001 ++ ++#endif /* _BRCM_SOC_H */ +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig.orig 2011-11-09 13:46:58.289800083 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig 2011-11-09 13:47:17.048565567 -0500 +@@ -0,0 +1,35 @@ ++config BRCMUTIL ++ tristate ++ ++config BRCMSMAC ++ tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" ++ depends on PCI ++ depends on MAC80211 ++ depends on BCMA=n ++ select BRCMUTIL ++ select FW_LOADER ++ select CRC_CCITT ++ select CRC8 ++ select CORDIC ++ ---help--- ++ This module adds support for PCIe wireless adapters based on Broadcom ++ IEEE802.11n SoftMAC chipsets. If you choose to build a module, it'll ++ be called brcmsmac.ko. ++ ++config BRCMFMAC ++ tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver" ++ depends on MMC ++ depends on CFG80211 ++ select BRCMUTIL ++ select FW_LOADER ++ ---help--- ++ This module adds support for embedded wireless adapters based on ++ Broadcom IEEE802.11n FullMAC chipsets. This driver uses the kernel's ++ wireless extensions subsystem. If you choose to build a module, ++ it'll be called brcmfmac.ko. ++ ++config BRCMDBG ++ bool "Broadcom driver debug functions" ++ depends on BRCMSMAC || BRCMFMAC ++ ---help--- ++ Selecting this enables additional code for debug purposes. +diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/Makefile.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/Makefile +--- linux-3.1.x86_64/drivers/net/wireless/brcm80211/Makefile.orig 2011-11-09 13:46:58.289800083 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/Makefile 2011-11-09 13:47:17.048565567 -0500 +@@ -0,0 +1,23 @@ ++# ++# Makefile fragment for Broadcom 802.11n Networking Device Driver ++# ++# Copyright (c) 2010 Broadcom Corporation ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# 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. ++ ++# common flags ++subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG ++ ++obj-$(CONFIG_BRCMUTIL) += brcmutil/ ++obj-$(CONFIG_BRCMFMAC) += brcmfmac/ ++obj-$(CONFIG_BRCMSMAC) += brcmsmac/ +diff -up linux-3.1.x86_64/drivers/net/wireless/Kconfig.orig linux-3.1.x86_64/drivers/net/wireless/Kconfig +--- linux-3.1.x86_64/drivers/net/wireless/Kconfig.orig 2011-11-09 13:48:16.411823422 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/Kconfig 2011-11-09 13:48:24.808718444 -0500 +@@ -271,6 +271,7 @@ config MWL8K + source "drivers/net/wireless/ath/Kconfig" + source "drivers/net/wireless/b43/Kconfig" + source "drivers/net/wireless/b43legacy/Kconfig" ++source "drivers/net/wireless/brcm80211/Kconfig" + source "drivers/net/wireless/hostap/Kconfig" + source "drivers/net/wireless/ipw2x00/Kconfig" + source "drivers/net/wireless/iwlwifi/Kconfig" +diff -up linux-3.1.x86_64/drivers/net/wireless/Makefile.orig linux-3.1.x86_64/drivers/net/wireless/Makefile +--- linux-3.1.x86_64/drivers/net/wireless/Makefile.orig 2011-11-09 13:47:55.028090756 -0500 ++++ linux-3.1.x86_64/drivers/net/wireless/Makefile 2011-11-09 13:47:49.856155362 -0500 +@@ -58,3 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl + obj-$(CONFIG_IWM) += iwmc3200wifi/ + + obj-$(CONFIG_MWIFIEX) += mwifiex/ ++ ++obj-$(CONFIG_BRCMFMAC) += brcm80211/ ++obj-$(CONFIG_BRCMSMAC) += brcm80211/ +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 06c9081..e2c3532 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -44,8 +44,6 @@ source "drivers/staging/wlan-ng/Kconfig" + + source "drivers/staging/echo/Kconfig" + +-source "drivers/staging/brcm80211/Kconfig" +- + source "drivers/staging/comedi/Kconfig" + + source "drivers/staging/olpc_dcon/Kconfig" +diff --git a/drivers/staging/brcm80211/Kconfig b/drivers/staging/brcm80211/Kconfig +deleted file mode 100644 +index 379cf16..0000000 +--- a/drivers/staging/brcm80211/Kconfig ++++ /dev/null +@@ -1,40 +0,0 @@ +-config BRCMUTIL +- tristate +- default n +- +-config BRCMSMAC +- tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" +- default n +- depends on PCI +- depends on WLAN && MAC80211 +- depends on X86 || MIPS +- select BRCMUTIL +- select FW_LOADER +- select CRC_CCITT +- ---help--- +- This module adds support for PCIe wireless adapters based on Broadcom +- IEEE802.11n SoftMAC chipsets. If you choose to build a module, it'll +- be called brcmsmac.ko. +- +-config BRCMFMAC +- tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver" +- default n +- depends on MMC +- depends on WLAN && CFG80211 +- depends on X86 || MIPS +- select BRCMUTIL +- select FW_LOADER +- select WIRELESS_EXT +- select WEXT_PRIV +- ---help--- +- This module adds support for embedded wireless adapters based on +- Broadcom IEEE802.11n FullMAC chipsets. This driver uses the kernel's +- wireless extensions subsystem. If you choose to build a module, +- it'll be called brcmfmac.ko. +- +-config BRCMDBG +- bool "Broadcom driver debug functions" +- default n +- depends on BRCMSMAC || BRCMFMAC +- ---help--- +- Selecting this enables additional code for debug purposes. +diff --git a/drivers/staging/brcm80211/Makefile b/drivers/staging/brcm80211/Makefile +deleted file mode 100644 +index 8b01f5e..0000000 +--- a/drivers/staging/brcm80211/Makefile ++++ /dev/null +@@ -1,24 +0,0 @@ +-# +-# Makefile fragment for Broadcom 802.11n Networking Device Driver +-# +-# Copyright (c) 2010 Broadcom Corporation +-# +-# Permission to use, copy, modify, and/or distribute this software for any +-# purpose with or without fee is hereby granted, provided that the above +-# 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. +- +-# common flags +-subdir-ccflags-y := -DBCMDMA32 +-subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG +- +-obj-$(CONFIG_BRCMUTIL) += brcmutil/ +-obj-$(CONFIG_BRCMFMAC) += brcmfmac/ +-obj-$(CONFIG_BRCMSMAC) += brcmsmac/ +diff --git a/drivers/staging/brcm80211/brcmfmac/Makefile b/drivers/staging/brcm80211/brcmfmac/Makefile +deleted file mode 100644 +index da3c805..0000000 +--- a/drivers/staging/brcm80211/brcmfmac/Makefile ++++ /dev/null +@@ -1,39 +0,0 @@ +-# +-# Makefile fragment for Broadcom 802.11n Networking Device Driver +-# +-# Copyright (c) 2010 Broadcom Corporation +-# +-# Permission to use, copy, modify, and/or distribute this software for any +-# purpose with or without fee is hereby granted, provided that the above +-# 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. +- +-ccflags-y := \ +- -DBRCMF_FIRSTREAD=64 \ +- -DBRCMF_SDALIGN=64 \ +- -DMAX_HDR_READ=64 +- +-ccflags-$(CONFIG_BRCMDBG) += -DSHOW_EVENTS +- +-ccflags-y += \ +- -Idrivers/staging/brcm80211/brcmfmac \ +- -Idrivers/staging/brcm80211/include +- +-DHDOFILES = \ +- wl_cfg80211.o \ +- dhd_cdc.o \ +- dhd_common.o \ +- dhd_sdio.o \ +- dhd_linux.o \ +- bcmsdh.o \ +- bcmsdh_sdmmc.o +- +-obj-$(CONFIG_BRCMFMAC) += brcmfmac.o +-brcmfmac-objs += $(DHDOFILES) +diff --git a/drivers/staging/brcm80211/brcmsmac/Makefile b/drivers/staging/brcm80211/brcmsmac/Makefile +deleted file mode 100644 +index 1ea3e0c..0000000 +--- a/drivers/staging/brcm80211/brcmsmac/Makefile ++++ /dev/null +@@ -1,58 +0,0 @@ +-# +-# Makefile fragment for Broadcom 802.11n Networking Device Driver +-# +-# Copyright (c) 2010 Broadcom Corporation +-# +-# Permission to use, copy, modify, and/or distribute this software for any +-# purpose with or without fee is hereby granted, provided that the above +-# 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. +- +-ccflags-y := \ +- -DWLC_HIGH \ +- -DWLC_LOW \ +- -DSTA \ +- -DWME \ +- -DWL11N \ +- -DDBAND \ +- -DBCMNVRAMR \ +- -Idrivers/staging/brcm80211/brcmsmac \ +- -Idrivers/staging/brcm80211/brcmsmac/phy \ +- -Idrivers/staging/brcm80211/include +- +-BRCMSMAC_OFILES := \ +- mac80211_if.o \ +- ucode_loader.o \ +- alloc.o \ +- ampdu.o \ +- antsel.o \ +- bmac.o \ +- channel.o \ +- main.o \ +- phy_shim.o \ +- pmu.o \ +- rate.o \ +- stf.o \ +- aiutils.o \ +- phy/phy_cmn.o \ +- phy/phy_lcn.o \ +- phy/phy_n.o \ +- phy/phytbl_lcn.o \ +- phy/phytbl_n.o \ +- phy/phy_qmath.o \ +- otp.o \ +- srom.o \ +- dma.o \ +- nicpci.o +- +-MODULEPFX := brcmsmac +- +-obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o +-$(MODULEPFX)-objs = $(BRCMSMAC_OFILES) +diff --git a/drivers/staging/brcm80211/brcmutil/Makefile b/drivers/staging/brcm80211/brcmutil/Makefile +deleted file mode 100644 +index 6403423..0000000 +--- a/drivers/staging/brcm80211/brcmutil/Makefile ++++ /dev/null +@@ -1,29 +0,0 @@ +-# +-# Makefile fragment for Broadcom 802.11n Networking Device Driver Utilities +-# +-# Copyright (c) 2011 Broadcom Corporation +-# +-# Permission to use, copy, modify, and/or distribute this software for any +-# purpose with or without fee is hereby granted, provided that the above +-# 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. +- +-ccflags-y := \ +- -Idrivers/staging/brcm80211/brcmutil \ +- -Idrivers/staging/brcm80211/include +- +-BRCMUTIL_OFILES := \ +- utils.o \ +- wifi.o +- +-MODULEPFX := brcmutil +- +-obj-$(CONFIG_BRCMUTIL) += $(MODULEPFX).o +-$(MODULEPFX)-objs = $(BRCMUTIL_OFILES) +-- +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index f3c5e33..f2c2209 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -14,8 +14,6 @@ obj-$(CONFIG_USBIP_CORE) += usbip/ + obj-$(CONFIG_W35UND) += winbond/ + obj-$(CONFIG_PRISM2_USB) += wlan-ng/ + obj-$(CONFIG_ECHO) += echo/ +-obj-$(CONFIG_BRCMSMAC) += brcm80211/ +-obj-$(CONFIG_BRCMFMAC) += brcm80211/ + obj-$(CONFIG_COMEDI) += comedi/ + obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ + obj-$(CONFIG_ASUS_OLED) += asus_oled/ diff --git a/config-arm b/config-arm deleted file mode 100644 index 1f26e7233..000000000 --- a/config-arm +++ /dev/null @@ -1,153 +0,0 @@ -CONFIG_ARM=y -CONFIG_SYS_SUPPORTS_APM_EMULATION=y -# CONFIG_SMP is not set - -# CONFIG_CMDLINE_FORCE is not set - -CONFIG_CC_OPTIMIZE_FOR_SIZE=y - -CONFIG_ARCH_VERSATILE=y -CONFIG_ARCH_VERSATILE_PB=y -CONFIG_MACH_VERSATILE_AB=y - -CONFIG_HIGHMEM=y -# CONFIG_HIGHPTE is not set - -# CONFIG_CPU_ICACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -# CONFIG_CPU_CACHE_ROUND_ROBIN is not set - -CONFIG_ZBOOT_ROM_TEXT=0 -CONFIG_ZBOOT_ROM_BSS=0 - -# CONFIG_XIP_KERNEL is not set - -CONFIG_ATAGS_PROC=y - -# CONFIG_FPE_NWFPE is not set -CONFIG_FPE_FASTFPE=y -CONFIG_VFP=y - -CONFIG_PM=y -# CONFIG_PM_DEBUG is not set -# CONFIG_PM_TRACE is not set -CONFIG_SUSPEND=y -# CONFIG_PM_TEST_SUSPEND is not set -CONFIG_APM_EMULATION=y - -CONFIG_ARM_THUMB=y - -CONFIG_AEABI=y -CONFIG_OABI_COMPAT=y - -# CONFIG_UACCESS_WITH_MEMCPY is not set - -CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/sda1 rootdelay=20" - -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y - -# CONFIG_CPU_IDLE is not set - -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y - -CONFIG_MTD_AFS_PARTS=y -CONFIG_MTD_ARM_INTEGRATOR=y -CONFIG_MTD_IMPA7=y - -CONFIG_AX88796=m -CONFIG_AX88796_93CX6=y -CONFIG_SMC91X=m -CONFIG_DM9000=m -CONFIG_DM9000_DEBUGLEVEL=4 -# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set -CONFIG_SMC911X=m -CONFIG_SMSC911X=m - -CONFIG_SERIO_AMBAKMI=m - -CONFIG_SERIAL_AMBA_PL011=y -CONFIG_SERIAL_AMBA_PL011_CONSOLE=y - -CONFIG_I2C_VERSATILE=y - -CONFIG_THERMAL=y - -# CONFIG_MFD_T7L66XB is not set -# CONFIG_MFD_TC6387XB is not set - -CONFIG_FB_ARMCLCD=m - -CONFIG_SND_ARM=y -CONFIG_SND_ARMAACI=m - -CONFIG_USB_MUSB_HDRC=y -# CONFIG_MUSB_PIO_ONLY is not set -CONFIG_USB_TUSB6010=y -# CONFIG_USB_MUSB_DEBUG is not set - -CONFIG_MMC_ARMMMCI=m -CONFIG_MMC_DW=m -# CONFIG_MMC_DW_IDMAC is not set - -CONFIG_RTC_DRV_PL030=m -CONFIG_RTC_DRV_PL031=m - -# CONFIG_SGI_IOC4 is not set - -# CONFIG_DEBUG_USER is not set -# CONFIG_DEBUG_ERRORS is not set -# CONFIG_DEBUG_LL is not set - -CONFIG_ARM_UNWIND=y - -CONFIG_RCU_FANOUT=32 - -# CONFIG_USB_ULPI is not set -# CONFIG_OC_ETM is not set - -# CONFIG_MTD_PISMO is not set - -CONFIG_PERF_EVENTS=y -CONFIG_PERF_COUNTERS=y - -# CONFIG_MG_DISK is not set -# CONFIG_GPIO_PL061 is not set - -CONFIG_CC_STACKPROTECTOR=y - -CONFIG_AUTO_ZRELADDR=y - -# CONFIG_ARM_CHARLCD is not set -# CONFIG_DEPRECATED_PARAM_STRUCT is not set - -# CONFIG_ARM_SP805_WATCHDOG is not set - -CONFIG_PM_OPP=y - -CONFIG_SECCOMP=y -CONFIG_STRICT_DEVMEM=y - -# CONFIG_AMBA_PL08X is not set - -# CONFIG_HVC_DCC is not set - -CONFIG_SPARSE_IRQ=y - -# CONFIG_ARM_PATCH_PHYS_VIRT is not set - -CONFIG_FTMAC100=m - -CONFIG_HWSPINLOCK_OMAP=m - -CONFIG_USE_OF=y -CONFIG_PROC_DEVICETREE=y -CONFIG_MTD_PHYSMAP_OF=m -CONFIG_SERIAL_OF_PLATFORM=m -CONFIG_MMC_SDHCI_OF=m -CONFIG_MMC_SDHCI_PXAV3=m -CONFIG_MMC_SDHCI_PXAV2=m - -CONFIG_FTGMAC100=m diff --git a/config-debug b/config-debug index 21e52bfd7..15a9aade2 100644 --- a/config-debug +++ b/config-debug @@ -24,6 +24,7 @@ CONFIG_FAIL_MAKE_REQUEST=y CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_FAIL_IO_TIMEOUT=y +CONFIG_FAIL_MMC_REQUEST=y CONFIG_SLUB_DEBUG_ON=y @@ -72,7 +73,7 @@ CONFIG_DEBUG_PERF_USE_VMALLOC=y CONFIG_JBD2_DEBUG=y -CONFIG_DEBUG_CFQ_IOSCHED=y +CONFIG_DEBUG_BLK_CGROUP=y CONFIG_DRBD_FAULT_INJECTION=y @@ -81,7 +82,6 @@ CONFIG_CARL9170_DEBUGFS=y CONFIG_IWLWIFI_DEVICE_TRACING=y CONFIG_DEBUG_OBJECTS_WORK=y -# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set CONFIG_DMADEVICES_DEBUG=y CONFIG_DMADEVICES_VDEBUG=y @@ -99,4 +99,17 @@ CONFIG_KDB_KEYBOARD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y CONFIG_TEST_LIST_SORT=y -CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set + +CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y + +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024 +# CONFIG_DEBUG_KMEMLEAK_TEST is not set +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y + +CONFIG_MAC80211_MESSAGE_TRACING=y + +CONFIG_EDAC_DEBUG=y diff --git a/config-generic b/config-generic index 6a4cf325b..afb70799b 100644 --- a/config-generic +++ b/config-generic @@ -32,20 +32,19 @@ CONFIG_KERNEL_GZIP=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_FHANDLE=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_BUF_SHIFT=18 # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set # CONFIG_EXPERT is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -69,6 +68,7 @@ CONFIG_SLUB=y CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set CONFIG_IWMC3200TOP=m # CONFIG_IWMC3200TOP_DEBUG is not set CONFIG_IWMC3200TOP_DEBUGFS=y @@ -81,7 +81,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_LOAD is not set # -- MODULE_FORCE_UNLOAD is controlled by config-debug/nodebug # CONFIG_MODVERSIONS is not set -CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_MODULE_SRCVERSION_ALL is not set # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) @@ -90,9 +90,11 @@ CONFIG_PCI=y # CONFIG_PCI_DEBUG is not set CONFIG_PCI_STUB=y CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y CONFIG_HT_IRQ=y CONFIG_PCI_MSI=y -CONFIG_PCI_MSI_DEFAULT_ON=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set CONFIG_PCIEPORTBUS=y CONFIG_PCIEAER=y CONFIG_PCIEASPM=y @@ -101,7 +103,6 @@ CONFIG_PCIE_ECRC=y CONFIG_PCIEAER_INJECT=m CONFIG_HOTPLUG_PCI_PCIE=y CONFIG_HOTPLUG_PCI_FAKE=m -CONFIG_PCI_LEGACY=y CONFIG_ISA=y # CONFIG_EISA is not set @@ -118,7 +119,6 @@ CONFIG_YENTA=m CONFIG_CARDBUS=y CONFIG_I82092=m CONFIG_PD6729=m -CONFIG_PCMCIA_IOCTL=y CONFIG_PCCARD=y CONFIG_MMC=m @@ -153,6 +153,7 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y CONFIG_INFINIBAND_IPOIB_CM=y CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_SRPT=m CONFIG_INFINIBAND_USER_MAD=m CONFIG_INFINIBAND_USER_ACCESS=m CONFIG_INFINIBAND_IPATH=m @@ -161,12 +162,14 @@ CONFIG_INFINIBAND_AMSO1100=m # CONFIG_INFINIBAND_AMSO1100_DEBUG is not set CONFIG_INFINIBAND_CXGB3=m CONFIG_INFINIBAND_CXGB4=m +CONFIG_SCSI_CXGB3_ISCSI=m CONFIG_SCSI_CXGB4_ISCSI=m # CONFIG_INFINIBAND_CXGB3_DEBUG is not set CONFIG_MLX4_INFINIBAND=m CONFIG_INFINIBAND_NES=m # CONFIG_INFINIBAND_NES_DEBUG is not set CONFIG_INFINIBAND_QIB=m +# CONFIG_INFINIBAND_OCRDMA is not set # # Executable file formats @@ -187,6 +190,8 @@ CONFIG_FW_LOADER=y # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_EXTRA_FIRMWARE="" +# CONFIG_CMA is not set + # CONFIG_SPI is not set # @@ -195,9 +200,7 @@ CONFIG_EXTRA_FIRMWARE="" CONFIG_MTD=m # CONFIG_MTD_DEBUG is not set CONFIG_MTD_SWAP=m -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_AR7_PARTS=m -CONFIG_MTD_CONCAT=m CONFIG_MTD_CMDLINE_PARTS=y # # User Modules And Translation Layers @@ -279,6 +282,7 @@ CONFIG_MTDRAM_ERASE_SIZE=128 # CONFIG_MTD_DOCPROBE is not set # CONFIG_MTD_DOCPROBE_ADVANCED is not set # CONFIG_MTD_DOCPROBE_ADDRESS is not set +# CONFIG_MTD_DOCG3 is not set # # NAND Flash Device Drivers @@ -298,6 +302,7 @@ CONFIG_MTD_NAND_CS553X=m CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018 # CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_RICOH=m +# CONFIG_MTD_NAND_DOCG4 is not set CONFIG_MTD_REDBOOT_PARTS=m # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set @@ -353,14 +358,19 @@ CONFIG_BLK_DEV_FD=m # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set + CONFIG_BLK_CPQ_DA=m CONFIG_BLK_CPQ_CISS_DA=m CONFIG_CISS_SCSI_TAPE=y CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DRBD=m CONFIG_BLK_DEV_UMEM=m CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_NVME is not set CONFIG_BLK_DEV_OSD=m CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 @@ -375,6 +385,7 @@ CONFIG_BLK_DEV_DELKIN=m # CONFIG_BLK_DEV_TC86C001 is not set CONFIG_LBDAF=y CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_THROTTLING=y @@ -433,14 +444,19 @@ CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_BLK_DEV_HD is not set +CONFIG_SCSI_VIRTIO=m CONFIG_VIRTIO_BLK=m CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_MMIO=m +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set CONFIG_VIRTIO_NET=m CONFIG_VMXNET3=m CONFIG_HW_RANDOM_VIRTIO=m CONFIG_VIRTIO_CONSOLE=y CONFIG_VHOST_NET=m +# CONFIG_TCM_VHOST is not set + # # SCSI device support @@ -486,7 +502,6 @@ CONFIG_SCSI_SAS_ATTRS=m CONFIG_SCSI_SRP_TGT_ATTRS=y CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SAS_ATA=y -# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set CONFIG_SCSI_SAS_HOST_SMP=y CONFIG_RAID_ATTRS=m @@ -503,15 +518,13 @@ CONFIG_SCSI_3W_9XXX=m CONFIG_SCSI_ACARD=m CONFIG_SCSI_AACRAID=m CONFIG_SCSI_AIC7XXX=m -CONFIG_SCSI_AIC94XX=m -# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set # CONFIG_AIC7XXX_DEBUG_ENABLE is not set CONFIG_AIC7XXX_DEBUG_MASK=0 # CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set -CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_SCSI_AIC79XX=m CONFIG_AIC79XX_CMDS_PER_DEVICE=4 CONFIG_AIC79XX_RESET_DELAY_MS=15000 @@ -519,6 +532,8 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set # CONFIG_SCSI_ADVANSYS is not set CONFIG_SCSI_BFA_FC=m CONFIG_MEGARAID_NEWGEN=y @@ -528,10 +543,15 @@ CONFIG_MEGARAID_LEGACY=m CONFIG_MEGARAID_SAS=m CONFIG_SCSI_MVSAS=m # CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVSAS_TASKLET=y CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 CONFIG_SCSI_MPT2SAS_LOGGING=y +CONFIG_SCSI_UFSHCD=m + +CONFIG_SCSI_MVUMI=m + CONFIG_SCSI_OSD_INITIATOR=m CONFIG_SCSI_OSD_ULD=m CONFIG_SCSI_OSD_DPRINT_SENSE=1 @@ -547,6 +567,60 @@ CONFIG_SCSI_PM8001=m CONFIG_VMWARE_PVSCSI=m CONFIG_VMWARE_BALLOON=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_FLASHPOINT=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_NSP32 is not set +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_LPFC_DEBUG_FS is not set + +# PCMCIA SCSI adapter support +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set + +# ISA SCSI Controllers. Sorry your life sucks. +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + + CONFIG_ATA=y CONFIG_ATA_BMDMA=y CONFIG_ATA_VERBOSE_ERROR=y @@ -626,48 +700,6 @@ CONFIG_PATA_VIA=m CONFIG_PATA_WINBOND=m CONFIG_PATA_ATP867X=m -CONFIG_SCSI_BUSLOGIC=m -CONFIG_SCSI_INITIO=m -CONFIG_SCSI_FLASHPOINT=y -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -CONFIG_SCSI_GDTH=m -CONFIG_SCSI_HPTIOP=m -CONFIG_SCSI_IPS=m -CONFIG_SCSI_INIA100=m -CONFIG_SCSI_PPA=m -CONFIG_SCSI_IMM=m -# CONFIG_SCSI_IZIP_EPP16 is not set -# CONFIG_SCSI_IZIP_SLOW_CTR is not set -CONFIG_SCSI_STEX=m -CONFIG_SCSI_SYM53C8XX_2=m -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -CONFIG_SCSI_SYM53C8XX_MMIO=y -CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_DC395x=m -# CONFIG_SCSI_NSP32 is not set -CONFIG_SCSI_DEBUG=m -CONFIG_SCSI_DC390T=m -CONFIG_SCSI_QLA_FC=m -CONFIG_SCSI_QLA_ISCSI=m -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_DPT_I2O is not set -CONFIG_SCSI_LPFC=m - -# -# PCMCIA SCSI adapter support -# -CONFIG_SCSI_LOWLEVEL_PCMCIA=y -CONFIG_PCMCIA_AHA152X=m -# CONFIG_PCMCIA_FDOMAIN is not set -CONFIG_PCMCIA_NINJA_SCSI=m -CONFIG_PCMCIA_QLOGIC=m -CONFIG_PCMCIA_SYM53C500=m - # # Multi-device support (RAID and LVM) @@ -691,6 +723,9 @@ CONFIG_DM_DEBUG=y CONFIG_DM_MIRROR=y CONFIG_DM_MULTIPATH=m CONFIG_DM_SNAPSHOT=y +CONFIG_DM_THIN_PROVISIONING=m +# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set +# CONFIG_DM_DEBUG_SPACE_MAPS is not set CONFIG_DM_UEVENT=y CONFIG_DM_ZERO=y CONFIG_DM_LOG_USERSPACE=m @@ -698,6 +733,7 @@ CONFIG_DM_MULTIPATH_QL=m CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_RAID=m CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m # # Fusion MPT device support @@ -725,7 +761,6 @@ CONFIG_FIREWIRE_NOSY=m # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support @@ -734,10 +769,16 @@ CONFIG_FIREWIRE_NOSY=m # CONFIG_I2O_LCT_NOTIFY_ON_CHANGES is not set # +# Virtualization support drivers +# +# CONFIG_VIRT_DRIVERS is not set + # Networking support # CONFIG_NET=y +CONFIG_NET_DMA=y + CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_CONG_BIC=m CONFIG_TCP_CONG_CUBIC=y @@ -758,14 +799,15 @@ CONFIG_TCP_MD5SIG=y # Networking options # CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y CONFIG_UNIX=y +CONFIG_UNIX_DIAG=m CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y CONFIG_INET_LRO=y CONFIG_INET_TUNNEL=m CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_FIB_TRIE_STATS=y @@ -784,6 +826,7 @@ CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y CONFIG_ARPD=y CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -803,6 +846,7 @@ CONFIG_IP_VS_PROTO_UDP=y CONFIG_IP_VS_PROTO_ESP=y CONFIG_IP_VS_PROTO_AH=y CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_IPV6=y CONFIG_IP_VS_RR=m CONFIG_IP_VS_WRR=m CONFIG_IP_VS_LC=m @@ -813,6 +857,13 @@ CONFIG_IP_VS_DH=m CONFIG_IP_VS_SH=m CONFIG_IP_VS_SED=m CONFIG_IP_VS_NQ=m + +# +# IPVS SH scheduler +# +# +CONFIG_IP_VS_SH_TAB_BITS=8 + CONFIG_IP_VS_FTP=m CONFIG_IP_VS_PE_SIP=m @@ -844,26 +895,38 @@ CONFIG_NET_9P_VIRTIO=m # CONFIG_NET_9P_DEBUG is not set CONFIG_NET_9P_RDMA=m -CONFIG_DECNET=m -CONFIG_DECNET_ROUTER=y -# CONFIG_DECNET_NF_GRABULATOR is not set +# CONFIG_DECNET is not set CONFIG_BRIDGE=m CONFIG_BRIDGE_IGMP_SNOOPING=y + +# PHY timestamping adds overhead # CONFIG_NETWORK_PHY_TIMESTAMPING is not set + CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y CONFIG_NF_CONNTRACK=m CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_ACCT=m CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_TPROXY=m CONFIG_NETFILTER_XTABLES=y CONFIG_NETFILTER_XT_SET=m CONFIG_NETFILTER_XT_MARK=m CONFIG_NETFILTER_XT_CONNMARK=m + +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m @@ -874,24 +937,33 @@ CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TEE=m -CONFIG_NETFILTER_XT_TARGET_LED=m -CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m + +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CPU=m CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ECN=m CONFIG_NETFILTER_XT_MATCH_ESP=m CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_HL=m CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m CONFIG_NETFILTER_XT_MATCH_LIMIT=m CONFIG_NETFILTER_XT_MATCH_MAC=m CONFIG_NETFILTER_XT_MATCH_MARK=m CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m CONFIG_NETFILTER_XT_MATCH_OWNER=m CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m @@ -899,23 +971,15 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=m CONFIG_NETFILTER_XT_MATCH_QUOTA=m CONFIG_NETFILTER_XT_MATCH_RATEEST=m CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=m CONFIG_NETFILTER_XT_MATCH_STRING=m CONFIG_NETFILTER_XT_MATCH_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_HL=m -CONFIG_NETFILTER_XT_MATCH_OSF=m -CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m -CONFIG_NETFILTER_XT_MATCH_CPU=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_TARGET_AUDIT=m -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -924,11 +988,11 @@ CONFIG_BRIDGE_NETFILTER=y # IP: Netfilter Configuration # -CONFIG_NF_CT_ACCT=y CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m @@ -941,6 +1005,7 @@ CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set CONFIG_NF_CONNTRACK_TIMESTAMP=y CONFIG_NF_CONNTRACK_SNMP=m CONFIG_NF_NAT=m @@ -948,11 +1013,13 @@ CONFIG_NF_NAT_SNMP_BASIC=m CONFIG_NF_CT_PROTO_DCCP=m CONFIG_NF_CT_PROTO_SCTP=m CONFIG_NF_CT_NETLINK=m +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NF_CT_NETLINK_HELPER=m CONFIG_NF_CT_PROTO_UDPLITE=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -985,6 +1052,7 @@ CONFIG_IP6_NF_MATCH_FRAG=m CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m CONFIG_IP6_NF_MATCH_OPTS=m CONFIG_IP6_NF_MATCH_RT=m CONFIG_IP6_NF_QUEUE=m @@ -1064,7 +1132,7 @@ CONFIG_LLC=m CONFIG_IPX=m # CONFIG_IPX_INTERN is not set CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=y +CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y CONFIG_IPDDP_DECAP=y @@ -1077,9 +1145,8 @@ CONFIG_IP_DCCP_CCID2=m # CONFIG_IP_DCCP_CCID2_DEBUG is not set CONFIG_IP_DCCP_CCID3=y # CONFIG_IP_DCCP_CCID3_DEBUG is not set -CONFIG_IP_DCCP_CCID3_RTO=100 # CONFIG_IP_DCCP_DEBUG is not set -CONFIG_NET_DCCPPROBE=m +# CONFIG_NET_DCCPPROBE is not set # # TIPC Configuration (EXPERIMENTAL) @@ -1109,8 +1176,12 @@ CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_TEQL=m CONFIG_NET_SCH_SFB=m CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_MULTIQ=m CONFIG_NET_SCH_CHOKE=m CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS=y CONFIG_NET_CLS_ACT=y CONFIG_NET_CLS_BASIC=m @@ -1132,8 +1203,10 @@ CONFIG_NET_EMATCH_META=m CONFIG_NET_EMATCH_NBYTE=m CONFIG_NET_EMATCH_STACK=32 CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_IPSET=m CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ACT_CSUM=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_IPT=m @@ -1142,9 +1215,12 @@ CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_SKBEDIT=m CONFIG_DCB=y +CONFIG_DNS_RESOLVER=m +CONFIG_OPENVSWITCH=m +CONFIG_NETPRIO_CGROUP=m # # Network testing @@ -1161,6 +1237,11 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_NET_TEAM_MODE_BROADCAST=m CONFIG_DUMMY=m CONFIG_BONDING=m CONFIG_MACVLAN=m @@ -1228,11 +1309,205 @@ CONFIG_RFKILL_INPUT=y # # Ethernet (10 or 100Mbit) # -CONFIG_NETDEV_1000=y -CONFIG_NETDEV_10000=y -CONFIG_NET_ETHERNET=y -CONFIG_PHYLIB=m + +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_ADAPTEC_STARFIRE=m + +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set + +CONFIG_NET_VENDOR_AMD=y +# CONFIG_LANCE is not set +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_PCMCIA_NMCLAN=m + +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1C=m +CONFIG_ATL1E=m + +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m +CONFIG_NET_CALXEDA_XGMAC=m + +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4VF=m + +# CONFIG_NET_VENDOR_CIRRUS is not set +# +CONFIG_NET_VENDOR_CISCO=y +CONFIG_ENIC=m + +CONFIG_NET_VENDOR_DEC=y +CONFIG_EWRK3=m +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_DE2104X_DSL=0 +CONFIG_TULIP=m +# CONFIG_TULIP_NAPI is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_NI5010 is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_ULI526X=m + +CONFIG_NET_VENDOR_DLINK=y +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set + +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m + +CONFIG_NET_VENDOR_EXAR=y +CONFIG_S2IO=m +CONFIG_VXGE=m +# CONFIG_VXGE_DEBUG_TRACE_ALL is not set + +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_FUJITSU is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGB_DCA=y +CONFIG_IGB_PTP=y +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBEVF=m +CONFIG_IXGBE=m +CONFIG_IXGBE_DCA=y +CONFIG_IXGBE_DCB=y +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_PTP=y + +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set + +CONFIG_NET_VENDOR_MICREL=y +CONFIG_KSZ884X_PCI=m +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set + +CONFIG_NET_VENDOR_MYRI=y +CONFIG_MYRI10GE=m +CONFIG_MYRI10GE_DCA=y + +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NATSEMI=m +CONFIG_NS83820=m + +CONFIG_NET_VENDOR_8390=y +# CONFIG_AC3200 is not set +CONFIG_PCMCIA_AXNET=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_PCMCIA_PCNET=m + +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=m + +CONFIG_NET_VENDOR_OKI=y +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PTP is not set + +CONFIG_NET_PACKET_ENGINE=y +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m + +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_QLGE=m +CONFIG_NETXEN_NIC=m + +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_ATP=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=m + +CONFIG_NET_VENDOR_RDC=y +CONFIG_R6040=m + +# CONFIG_NET_VENDOR_SEEQ is not set + +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m + +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m + +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC9194 is not set +CONFIG_PCMCIA_SMC91C92=m +CONFIG_EPIC100=m +CONFIG_SMSC9420=m + +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_STMMAC_ETH=m +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_DA is not set +# CONFIG_STMMAC_DUAL_MAC is not set +# CONFIG_STMMAC_TIMER is not set +# CONFIG_STMMAC_DEBUG_FS is not set + +CONFIG_NET_VENDOR_SUN=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m + +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_TEHUTI=m + +CONFIG_NET_VENDOR_TI=y +CONFIG_TLAN=m + +CONFIG_NET_VENDOR_VIA=y +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m + +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5300=m + +CONFIG_NET_VENDOR_XIRCOM=y +CONFIG_PCMCIA_XIRC2PS=m + +CONFIG_PHYLIB=y +CONFIG_AMD_PHY=m CONFIG_BROADCOM_PHY=m +CONFIG_BCM87XX_PHY=m CONFIG_CICADA_PHY=m CONFIG_DAVICOM_PHY=m CONFIG_FIXED_PHY=y @@ -1251,146 +1526,46 @@ CONFIG_VITESSE_PHY=m CONFIG_MICREL_PHY=m CONFIG_MII=m -CONFIG_HAPPYMEAL=m -CONFIG_SUNGEM=m CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=m CONFIG_TYPHOON=m CONFIG_DNET=m -CONFIG_STMMAC_ETH=m -# CONFIG_STMMAC_DA is not set -# CONFIG_STMMAC_DUAL_MAC is not set -# CONFIG_STMMAC_TIMER is not set -# CONFIG_PCH_GBE is not set -# -# Tulip family network device support -# -CONFIG_NET_TULIP=y -CONFIG_DE2104X=m -CONFIG_DE2104X_DSL=0 -CONFIG_TULIP=m -# CONFIG_TULIP_NAPI is not set -# CONFIG_TULIP_MWI is not set -CONFIG_TULIP_MMIO=y -# CONFIG_NI5010 is not set -CONFIG_DE4X5=m -CONFIG_WINBOND_840=m -CONFIG_DM9102=m -CONFIG_PCMCIA_XIRCOM=m -CONFIG_ULI526X=m -# CONFIG_HP100 is not set CONFIG_LNE390=m -CONFIG_NE3210=m CONFIG_ES3210=m CONFIG_NET_PCI=y -CONFIG_PCNET32=m -CONFIG_AMD8111_ETH=m -CONFIG_ADAPTEC_STARFIRE=m -CONFIG_KSZ884X_PCI=m CONFIG_B44=m CONFIG_B44_PCI=y CONFIG_BNX2=m CONFIG_CNIC=m -CONFIG_QLA3XXX=m -CONFIG_ATL1=m -CONFIG_ATL1C=m -CONFIG_ATL2=m -CONFIG_ATL1E=m -CONFIG_E100=m CONFIG_FEALNX=m -CONFIG_FORCEDETH=m -CONFIG_FORCEDETH_NAPI=y -CONFIG_NATSEMI=m -CONFIG_NE2K_PCI=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -CONFIG_8139TOO_8129=y -# CONFIG_8139_OLD_RX_RESET is not set -CONFIG_SIS900=m -CONFIG_SIS190=m -CONFIG_EPIC100=m -CONFIG_SC92031=m -CONFIG_SMSC9420=m -CONFIG_SUNDANCE=m -# CONFIG_SUNDANCE_MMIO is not set -CONFIG_TLAN=m -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y -CONFIG_VIA_VELOCITY=m CONFIG_NET_POCKET=y -CONFIG_ATP=m -CONFIG_DE600=m -CONFIG_DE620=m -CONFIG_CASSINI=m CONFIG_ETHOC=m -# CONFIG_KS8842 is not set -# CONFIG_KS8851_MLL is not set # # Ethernet (1000 Mbit) # -CONFIG_ACENIC=m -# CONFIG_ACENIC_OMIT_TIGON_I is not set -CONFIG_DL2K=m -CONFIG_E1000=m -CONFIG_E1000E=m -CONFIG_IGB=m -CONFIG_IGB_DCA=y -CONFIG_IGBVF=m -CONFIG_NS83820=m -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m -CONFIG_R8169=m -CONFIG_R8169_VLAN=y -CONFIG_SKGE=m -# CONFIG_SKGE_DEBUG is not set -CONFIG_SKGE_GENESIS=y CONFIG_TIGON3=m -CONFIG_SKY2=m -# CONFIG_SKY2_DEBUG is not set CONFIG_JME=m # # Ethernet (10000 Mbit) # -CONFIG_CHELSIO_T1=m -CONFIG_CHELSIO_T1_1G=y -CONFIG_CHELSIO_T3=m -CONFIG_CHELSIO_T4=m -CONFIG_CHELSIO_T4VF=m CONFIG_IP1000=m -CONFIG_IXGB=m -CONFIG_IXGBEVF=m -CONFIG_IXGBE=m -CONFIG_IXGBE_DCA=y -CONFIG_IXGBE_DCB=y -CONFIG_MYRI10GE=m -CONFIG_MYRI10GE_DCA=y -CONFIG_NETXEN_NIC=m -CONFIG_NIU=m -CONFIG_S2IO=m -CONFIG_VXGE=m -# CONFIG_VXGE_DEBUG_TRACE_ALL is not set -CONFIG_TEHUTI=m -CONFIG_ENIC=m CONFIG_MLX4_EN=m +CONFIG_MLX4_EN_DCB=y # CONFIG_MLX4_DEBUG is not set -CONFIG_QLCNIC=m -CONFIG_QLGE=m -CONFIG_BNA=m CONFIG_SFC=m +CONFIG_SFC_MCDI_MON=y +CONFIG_SFC_SRIOV=y CONFIG_SFC_MTD=y -CONFIG_BE2NET=m -CONFIG_FDDI=y +# CONFIG_FDDI is not set # CONFIG_DEFXX is not set -CONFIG_SKFP=m +# CONFIG_SKFP is not set # CONFIG_HIPPI is not set -CONFIG_PLIP=m +# CONFIG_PLIP is not set CONFIG_PPP=m CONFIG_PPP_MULTILINK=y CONFIG_PPP_FILTER=y @@ -1398,9 +1573,10 @@ CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_PPP_DEFLATE=m CONFIG_IPPP_FILTER=y -# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPP_BSDCOMP=y CONFIG_PPPOE=m CONFIG_PPP_MPPE=m +#Added back for F16 CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y @@ -1412,9 +1588,6 @@ CONFIG_SLIP_SMART=y # CONFIG_WLAN=y # CONFIG_STRIP is not set -# CONFIG_ARLAN is not set -CONFIG_PCMCIA_WAVELAN=m -CONFIG_PCMCIA_NETWAVE=m # CONFIG_PCMCIA_RAYCS is not set CONFIG_WIRELESS=y @@ -1426,7 +1599,6 @@ CONFIG_CFG80211_DEBUGFS=y CONFIG_CFG80211_DEFAULT_PS=y CONFIG_NL80211=y # CONFIG_NL80211_TESTMODE is not set -# CONFIG_WIRELESS_OLD_REGULATORY is not set CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=m @@ -1457,16 +1629,23 @@ CONFIG_ATH_COMMON=m CONFIG_ATH5K=m CONFIG_ATH5K_DEBUG=y # CONFIG_ATH5K_TRACER is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_DEBUG=y +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m CONFIG_ATH9K=m CONFIG_ATH9K_PCI=y CONFIG_ATH9K_AHB=y # CONFIG_ATH9K_DEBUG is not set +# CONFIG_ATH9K_MAC_DEBUG is not set CONFIG_ATH9K_DEBUGFS=y CONFIG_ATH9K_HTC=m +CONFIG_ATH9K_BTCOEX_SUPPORT=y # CONFIG_ATH9K_HTC_DEBUGFS is not set CONFIG_ATH9K_RATE_CONTROL=y CONFIG_CARL9170=m CONFIG_CARL9170_LEDS=y +# CONFIG_CARL9170_HWRNG is not set CONFIG_AT76C50X_USB=m CONFIG_AIRO=m CONFIG_AIRO_CS=m @@ -1474,17 +1653,27 @@ CONFIG_ATMEL=m CONFIG_B43=m CONFIG_B43_PCMCIA=y CONFIG_B43_SDIO=y -CONFIG_B43_DEBUG=y +CONFIG_B43_BCMA=y +# CONFIG_B43_BCMA_EXTRA is not set +CONFIG_B43_BCMA_PIO=y +# CONFIG_B43_DEBUG is not set CONFIG_B43_PHY_LP=y CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_HT=y # CONFIG_B43_FORCE_PIO is not set CONFIG_B43LEGACY=m -CONFIG_B43LEGACY_DEBUG=y +# CONFIG_B43LEGACY_DEBUG is not set CONFIG_B43LEGACY_DMA=y CONFIG_B43LEGACY_PIO=y CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y # CONFIG_B43LEGACY_DMA_MODE is not set # CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_SDIO=y +CONFIG_BRCMFMAC_SDIO_OOB=y +CONFIG_BRCMFMAC_USB=y +# CONFIG_BRCMDBG is not set CONFIG_HERMES=m CONFIG_HERMES_CACHE_FW_ON_INIT=y # CONFIG_HERMES_PRISM is not set @@ -1516,18 +1705,15 @@ CONFIG_LIBERTAS_MESH=y CONFIG_IWLWIFI=m CONFIG_IWLWIFI_DEBUG=y CONFIG_IWLWIFI_DEBUGFS=y -CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT=y CONFIG_IWLWIFI_DEVICE_SVTOOL=y -# CONFIG_IWL_P2P is not set -CONFIG_IWLAGN=m -CONFIG_IWLWIFI_LEGACY=m -CONFIG_IWLWIFI_LEGACY_DEBUG=y -CONFIG_IWLWIFI_LEGACY_DEBUGFS=y +# CONFIG_IWLWIFI_EXPERIMENTAL_MFP is not set +# CONFIG_IWLWIFI_P2P is not set +CONFIG_IWLEGACY=m +CONFIG_IWLEGACY_DEBUG=y +CONFIG_IWLEGACY_DEBUGFS=y # CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set CONFIG_IWL4965=y -CONFIG_IWL5000=y CONFIG_IWL3945=m -CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y # CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set CONFIG_IWM=m # CONFIG_IWM_DEBUG is not set @@ -1550,6 +1736,7 @@ CONFIG_RT2500PCI=m CONFIG_RT61PCI=m CONFIG_RT2500USB=m CONFIG_RT2800USB=m +CONFIG_RT2800PCI_RT3290=y CONFIG_RT2800USB_RT33XX=y CONFIG_RT2800USB_RT35XX=y CONFIG_RT2800USB_RT53XX=y @@ -1561,14 +1748,16 @@ CONFIG_RT2800PCI_RT53XX=y CONFIG_RT73USB=m CONFIG_RTL8180=m CONFIG_RTL8187=m +# CONFIG_RTLWIFI_DEBUG is not set CONFIG_TMD_HERMES=m CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m CONFIG_USB_NET_SMSC75XX=m +# CONFIG_WL_TI is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set -CONFIG_AR9170_USB=m CONFIG_WL12XX_MENU=m CONFIG_WL12XX=m @@ -1580,9 +1769,6 @@ CONFIG_WL12XX_SDIO=m CONFIG_WL1251=m CONFIG_WL1251_SPI=m CONFIG_WL1251_SDIO=m -CONFIG_WL1271=m -CONFIG_WL1271_SDIO=m -CONFIG_WL1271_SPI=m CONFIG_RTL8192CE=m CONFIG_RTL8192SE=m @@ -1591,20 +1777,13 @@ CONFIG_RTL8192DE=m CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m +CONFIG_MWIFIEX_USB=m # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_IBMOL is not set -# CONFIG_3C359 is not set -# Broken with gcc4.1 -# CONFIG_TMS380TR is not set -# CONFIG_TMSPCI is not set -# CONFIG_ABYSS is not set -# CONFIG_IBMLS is not set -# CONFIG_PCMCIA_IBMTR is not set - CONFIG_NET_FC=y @@ -1620,11 +1799,6 @@ CONFIG_NET_PCMCIA=y CONFIG_PCMCIA_3C589=m CONFIG_PCMCIA_3C574=m CONFIG_PCMCIA_FMVJ18X=m -CONFIG_PCMCIA_PCNET=m -CONFIG_PCMCIA_NMCLAN=m -CONFIG_PCMCIA_SMC91C92=m -CONFIG_PCMCIA_XIRC2PS=m -CONFIG_PCMCIA_AXNET=m # # Amateur Radio support @@ -1632,27 +1806,9 @@ CONFIG_PCMCIA_AXNET=m CONFIG_HAMRADIO=y CONFIG_AX25=m CONFIG_AX25_DAMA_SLAVE=y -CONFIG_CAN=m -CONFIG_CAN_RAW=m -CONFIG_CAN_BCM=m -CONFIG_CAN_VCAN=m -CONFIG_CAN_DEV=m -CONFIG_CAN_CALC_BITTIMING=y -CONFIG_CAN_SJA1000=m -CONFIG_CAN_SJA1000_ISA=m -CONFIG_CAN_SJA1000_PLATFORM=m -CONFIG_CAN_EMS_PCI=m -CONFIG_CAN_EMS_USB=m -CONFIG_CAN_ESD_USB2=m -CONFIG_CAN_KVASER_PCI=m -CONFIG_CAN_PLX_PCI=m -CONFIG_CAN_TSCAN1=m -CONFIG_CAN_SLCAN=m -CONFIG_CAN_SOFTING=m -CONFIG_CAN_SOFTING_CS=m -CONFIG_CAN_C_CAN=m -CONFIG_CAN_C_CAN_PLATFORM=m -# CONFIG_PCH_CAN is not set + +# CONFIG_CAN is not set + CONFIG_NETROM=m CONFIG_ROSE=m CONFIG_MKISS=m @@ -1668,7 +1824,7 @@ CONFIG_BAYCOM_PAR=m CONFIG_BAYCOM_EPP=m CONFIG_YAM=m -CONFIG_NFC=m +# CONFIG_NFC is not set # # IrDA (infrared) support @@ -1713,7 +1869,6 @@ CONFIG_WINBOND_FIR=m # CONFIG_BT=m CONFIG_BT_L2CAP=y -CONFIG_BT_L2CAP_EXT_FEATURES=y CONFIG_BT_SCO=y CONFIG_BT_CMTP=m CONFIG_BT_RFCOMM=m @@ -1733,6 +1888,7 @@ CONFIG_BT_HCIUART=m CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_3WIRE=y CONFIG_BT_HCIDTL1=m CONFIG_BT_HCIBT3C=m CONFIG_BT_HCIBLUECARD=m @@ -1838,8 +1994,6 @@ CONFIG_ISDN_CAPI=m CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y CONFIG_ISDN_CAPI_MIDDLEWARE=y CONFIG_ISDN_CAPI_CAPI20=m -CONFIG_ISDN_CAPI_CAPIFS_BOOL=y -CONFIG_ISDN_CAPI_CAPIFS=m # # CAPI hardware drivers @@ -1889,6 +2043,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_MATRIXKMAP is not set CONFIG_INPUT_TABLET=y CONFIG_TABLET_USB_ACECAD=m @@ -1904,6 +2059,7 @@ CONFIG_INPUT_CM109=m CONFIG_INPUT_POLLDEV=m CONFIG_INPUT_SPARSEKMAP=m # CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_BMA150 is not set CONFIG_INPUT_CMA3000=m CONFIG_INPUT_CMA3000_I2C=m @@ -1938,6 +2094,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set # CONFIG_KEYBOARD_ADP5588 is not set # CONFIG_KEYBOARD_MAX7359 is not set # CONFIG_KEYBOARD_ADP5589 is not set @@ -1945,8 +2102,11 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_QT1070 is not set # CONFIG_KEYBOARD_MCS is not set # CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set # CONFIG_KEYBOARD_QT2160 is not set # CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_OMAP4 is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_PS2_TOUCHKIT is not set @@ -1957,6 +2117,7 @@ CONFIG_MOUSE_VSXXXAA=m CONFIG_MOUSE_APPLETOUCH=m CONFIG_MOUSE_BCM5974=m CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_ANALOG=m CONFIG_JOYSTICK_A3D=m @@ -1993,26 +2154,33 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_AD7879 is not set CONFIG_TOUCHSCREEN_AD7879_I2C=m # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_EGALAX=m CONFIG_TOUCHSCREEN_ELO=m CONFIG_TOUCHSCREEN_FUJITSU=m CONFIG_TOUCHSCREEN_GUNZE=m # CONFIG_TOUCHSCREEN_HAMPSHIRE is not set CONFIG_TOUCHSCREEN_HTCPEN=m CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_ILI210X=m +CONFIG_TOUCHSCREEN_MMS114=m CONFIG_TOUCHSCREEN_MTOUCH=m CONFIG_TOUCHSCREEN_MCS5000=m CONFIG_TOUCHSCREEN_MK712=m -# CONFIG_TOUCHSCREEN_QT602240 is not set CONFIG_TOUCHSCREEN_PENMOUNT=m # CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_TSC_SERIO=m CONFIG_TOUCHSCREEN_TSC2007=m CONFIG_TOUCHSCREEN_TOUCHIT213=m CONFIG_TOUCHSCREEN_TOUCHRIGHT=m CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_PIXCIR=m CONFIG_TOUCHSCREEN_UCB1400=m CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m CONFIG_TOUCHSCREEN_USB_E2I=y CONFIG_TOUCHSCREEN_USB_COMPOSITE=m # CONFIG_TOUCHSCREEN_WM97XX is not set @@ -2028,7 +2196,6 @@ CONFIG_INPUT_UINPUT=m CONFIG_INPUT_WISTRON_BTNS=m CONFIG_INPUT_ATLAS_BTNS=m -CONFIG_INPUT_ATI_REMOTE=m CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m @@ -2036,10 +2203,13 @@ CONFIG_MAC_EMUMOUSEBTN=y CONFIG_INPUT_WM831X_ON=m -CONFIG_INPUT_APPLEIR=m # CONFIG_INPUT_AD714X is not set # CONFIG_INPUT_PCF8574 is not set +CONFIG_INPUT_MMA8450=m +CONFIG_INPUT_MPU3050=m +CONFIG_INPUT_KXTJ9=m +# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set # # Character devices @@ -2080,19 +2250,13 @@ CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set CONFIG_SERIAL_8250_RSA=y -# CONFIG_COMPUTONE is not set +# CONFIG_SERIAL_8250_DW is not set CONFIG_CYCLADES=m # CONFIG_CYZ_INTR is not set -# CONFIG_DIGIEPCA is not set # CONFIG_MOXA_INTELLIO is not set # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set -# CONFIG_RISCOM8 is not set -# CONFIG_SPECIALIX is not set -# CONFIG_SX is not set # CONFIG_RIO is not set -# CONFIG_STALLION is not set -# CONFIG_ISTALLION is not set CONFIG_SERIAL_JSM=m # CONFIG_SERIAL_MFD_HSU is not set @@ -2143,7 +2307,6 @@ CONFIG_I2C_ALGOPCA=m # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set # CONFIG_I2C_ELEKTOR is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_ISCH is not set @@ -2196,7 +2359,6 @@ CONFIG_SENSORS_ADM9240=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_ADT7462=m CONFIG_SENSORS_ADT7470=m -CONFIG_SENSORS_ADT7473=m CONFIG_SENSORS_ADT7475=m CONFIG_SENSORS_APPLESMC=m CONFIG_SENSORS_ASB100=m @@ -2213,6 +2375,7 @@ CONFIG_SENSORS_G760A=m CONFIG_SENSORS_GL518SM=m CONFIG_SENSORS_GL520SM=m CONFIG_SENSORS_HDAPS=m +# CONFIG_SENSORS_HIH6130 is not set # CONFIG_SENSORS_I5K_AMB is not set # FIXME: IBMAEM x86 only? CONFIG_SENSORS_IBMAEM=m @@ -2236,11 +2399,14 @@ CONFIG_SENSORS_LM93=m CONFIG_SENSORS_LTC4245=m CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MCP3021=m +CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_PC87360=m CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_PCF8591=m CONFIG_SENSORS_SHT15=m CONFIG_SENSORS_SIS5595=m +CONFIG_CHARGER_SMB347=m CONFIG_SENSORS_SMSC47M1=m CONFIG_SENSORS_SMSC47M192=m CONFIG_SENSORS_SMSC47B397=m @@ -2266,11 +2432,13 @@ CONFIG_SENSORS_W83792D=m CONFIG_SENSORS_W83793=m CONFIG_SENSORS_LTC4215=m CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m CONFIG_SENSORS_TMP421=m CONFIG_SENSORS_WM8350=m CONFIG_SENSORS_WM831X=m CONFIG_SENSORS_LM73=m CONFIG_SENSORS_AMC6821=m +CONFIG_SENSORS_INA2XX=m CONFIG_SENSORS_ADT7411=m CONFIG_SENSORS_ASC7621=m CONFIG_SENSORS_EMC1403=m @@ -2289,44 +2457,33 @@ CONFIG_SENSORS_LINEAGE=m CONFIG_SENSORS_LTC4151=m CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m CONFIG_SENSORS_ADS1015=m CONFIG_SENSORS_MAX16065=m CONFIG_SENSORS_MAX6642=m CONFIG_SENSORS_ADM1275=m CONFIG_SENSORS_UCD9000=m CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_ZL6100=m CONFIG_SENSORS_EMC6W201=m CONFIG_PMBUS=m CONFIG_SENSORS_PMBUS=m CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LTC2978=m CONFIG_SENSORS_MAX34440=m CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_MAX1668=m # CONFIG_HMC6352 is not set # CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set # CONFIG_PCH_PHUB is not set # CONFIG_SERIAL_PCH_UART is not set +# CONFIG_USB_SWITCH_FSA9480 is not set -CONFIG_W1=m -CONFIG_W1_CON=y -# This is busted. -# If we enable it, it steals Matrox cards, and the -# framebuffer drivers stop working. -# CONFIG_W1_MASTER_MATROX is not set -CONFIG_W1_MASTER_DS2482=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS1WM=m -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2431=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y -CONFIG_W1_SLAVE_DS2760=m -CONFIG_W1_SLAVE_DS2423=m -CONFIG_W1_SLAVE_DS2408=m -CONFIG_W1_SLAVE_DS2780=m -CONFIG_W1_SLAVE_BQ27000=m +# CONFIG_W1 is not set # # Mice @@ -2346,6 +2503,7 @@ CONFIG_IPMI_POWEROFF=m # Watchdog Cards # CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y # CONFIG_WATCHDOG_NOWAYOUT is not set CONFIG_SOFT_WATCHDOG=m CONFIG_WDTPCI=m @@ -2362,6 +2520,7 @@ CONFIG_MACHZ_WDT=m # CONFIG_SC520_WDT is not set CONFIG_ALIM7101_WDT=m CONFIG_ALIM1535_WDT=m +CONFIG_IT87_WDT=m CONFIG_ITCO_WDT=m CONFIG_ITCO_VENDOR_SUPPORT=y # CONFIG_SC1200_WDT is not set @@ -2375,11 +2534,15 @@ CONFIG_IT8712F_WDT=m CONFIG_SMSC_SCH311X_WDT=m CONFIG_W83977F_WDT=m CONFIG_PCIPCWATCHDOG=m +# CONFIG_PCWATCHDOG is not set CONFIG_USBPCWATCHDOG=m # CONFIG_SBC_EPX_C3_WATCHDOG is not set CONFIG_WM8350_WATCHDOG=m CONFIG_WM831X_WATCHDOG=m # CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_W83697UG_WDT=m +# CONFIG_WDT is not set CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_TIMERIOMEM=m @@ -2396,6 +2559,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1511=m CONFIG_RTC_DRV_DS1553=m CONFIG_RTC_DRV_DS1672=m CONFIG_RTC_DRV_DS1742=m @@ -2453,14 +2617,18 @@ CONFIG_AGP_EFFICEON=y CONFIG_VGA_ARB=y CONFIG_VGA_ARB_MAX_GPUS=16 CONFIG_STUB_POULSBO=m +# CONFIG_DRM_PSB is not set CONFIG_DRM=m +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m +# CONFIG_DRM_AST is not set +# CONFIG_DRM_CIRRUS_QEMU is not set CONFIG_DRM_RADEON=m CONFIG_DRM_RADEON_KMS=y CONFIG_DRM_I810=m -# CONFIG_DRM_I830 is not set CONFIG_DRM_MGA=m +# CONFIG_DRM_MGAG200 is not set CONFIG_DRM_SIS=m CONFIG_DRM_SAVAGE=m CONFIG_DRM_I915=m @@ -2471,7 +2639,9 @@ CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_DEBUG=y CONFIG_DRM_I2C_CH7006=m CONFIG_DRM_I2C_SIL164=m +# CONFIG_DRM_UDL is not set CONFIG_DRM_VMWGFX=m +# CONFIG_DRM_VMWGFX_FBCON is not set # # PCMCIA character devices @@ -2490,12 +2660,15 @@ CONFIG_HANGCHECK_TIMER=m # Multimedia devices # CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_DEV=m # CONFIG_VIDEO_ADV_DEBUG is not set CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -CONFIG_VIDEO_ALLOW_V4L1=y -CONFIG_VIDEO_V4L1_COMPAT=y CONFIG_VIDEO_V4L2=y CONFIG_VIDEO_V4L2_SUBDEV_API=y # CONFIG_VIDEO_VIVI is not set @@ -2509,6 +2682,7 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y # CONFIG_V4L_USB_DRIVERS=y CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_V4L_PCI_DRIVERS=y CONFIG_VIDEO_AU0828=m CONFIG_VIDEO_BT848=m CONFIG_VIDEO_BT848_DVB=y @@ -2520,7 +2694,7 @@ CONFIG_VIDEO_CAFE_CCIC=m CONFIG_VIDEO_CPIA2=m CONFIG_VIDEO_CQCAM=m CONFIG_VIDEO_CX23885=m -# CONFIG_MEDIA_ALTERA_CI is not set +CONFIG_MEDIA_ALTERA_CI=m CONFIG_VIDEO_CX18=m CONFIG_VIDEO_CX18_ALSA=m CONFIG_VIDEO_CX88=m @@ -2531,6 +2705,7 @@ CONFIG_VIDEO_CX88_VP3054=m CONFIG_VIDEO_EM28XX=m CONFIG_VIDEO_EM28XX_ALSA=m CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=y CONFIG_VIDEO_CX231XX=m CONFIG_VIDEO_CX231XX_ALSA=m CONFIG_VIDEO_CX231XX_DVB=m @@ -2540,17 +2715,14 @@ CONFIG_VIDEO_HEXIUM_GEMINI=m CONFIG_VIDEO_IVTV=m CONFIG_VIDEO_MEYE=m CONFIG_VIDEO_MXB=m -# CONFIG_VIDEO_OVCAMCHIP is not set CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PMS is not set CONFIG_VIDEO_HDPVR=m -CONFIG_VIDEO_SAA5246A=m -CONFIG_VIDEO_SAA5249=m CONFIG_VIDEO_SAA6588=m CONFIG_VIDEO_SAA7134=m CONFIG_VIDEO_SAA7134_ALSA=m CONFIG_VIDEO_SAA7134_DVB=m CONFIG_VIDEO_SAA7134_RC=y -CONFIG_VIDEO_STRADIS=m CONFIG_VIDEO_USBVISION=m CONFIG_VIDEO_W9966=m CONFIG_VIDEO_ZORAN=m @@ -2561,11 +2733,26 @@ CONFIG_VIDEO_ZORAN_DC30=m CONFIG_VIDEO_ZORAN_LML33=m CONFIG_VIDEO_ZORAN_LML33R10=m CONFIG_VIDEO_ZORAN_ZR36060=m +# CONFIG_V4L_ISA_PARPORT_DRIVERS is not set +# CONFIG_V4L_PLATFORM_DRIVERS is not set CONFIG_VIDEO_FB_IVTV=m CONFIG_VIDEO_SAA7164=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m CONFIG_VIDEO_TLG2300=m +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set + +CONFIG_IR_GPIO_CIR=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_USB_KEENE=n + # CONFIG_VIDEO_TIMBERDALE is not set # CONFIG_VIDEO_M5MOLS is not set +# CONFIG_EXYNOS_VIDEO is not set CONFIG_USB_VIDEO_CLASS=m CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y @@ -2573,107 +2760,31 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # # Radio Adapters # -CONFIG_RADIO_GEMTEK_PCI=m CONFIG_RADIO_MAXIRADIO=m -CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m CONFIG_RADIO_WL1273=m CONFIG_RADIO_WL128X=m CONFIG_MEDIA_ATTACH=y -CONFIG_MEDIA_TUNER_CUSTOMISE=y -CONFIG_MEDIA_TUNER_SIMPLE=m -CONFIG_MEDIA_TUNER_TDA8290=m -CONFIG_MEDIA_TUNER_TEA5761=m -CONFIG_MEDIA_TUNER_TEA5767=m -CONFIG_MEDIA_TUNER_MT20XX=m -CONFIG_MEDIA_TUNER_MT2060=m -CONFIG_MEDIA_TUNER_MT2266=m -CONFIG_MEDIA_TUNER_MT2131=m -CONFIG_MEDIA_TUNER_QT1010=m -CONFIG_MEDIA_TUNER_XC2028=m -CONFIG_MEDIA_TUNER_XC5000=m -CONFIG_MEDIA_TUNER_MXL5005S=m -CONFIG_MEDIA_TUNER_MXL5007T=m -CONFIG_MEDIA_TUNER_MC44S803=m -CONFIG_MEDIA_TUNER_MAX2165=m -CONFIG_MEDIA_TUNER_TDA18218=m -CONFIG_MEDIA_TUNER_TDA18212=m +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set # # Digital Video Broadcasting Devices # CONFIG_DVB_CAPTURE_DRIVERS=y CONFIG_DVB_CORE=m +CONFIG_DVB_NET=y CONFIG_DVB_MAX_ADAPTERS=8 CONFIG_DVB_DYNAMIC_MINORS=y -CONFIG_DVB_FE_CUSTOMISE=y -CONFIG_DVB_STB0899=m -CONFIG_DVB_STB6100=m -CONFIG_DVB_STV090x=m -CONFIG_DVB_STV6110x=m -CONFIG_DVB_CX24110=m -CONFIG_DVB_CX24123=m -CONFIG_DVB_MT312=m -CONFIG_DVB_ZL10036=m -CONFIG_DVB_ZL10039=m -CONFIG_DVB_S5H1420=m -CONFIG_DVB_STV0288=m -CONFIG_DVB_STB6000=m -CONFIG_DVB_STV6110=m -CONFIG_DVB_STV0900=m -CONFIG_DVB_TDA8083=m -CONFIG_DVB_TDA10086=m -CONFIG_DVB_TDA8261=m -CONFIG_DVB_VES1X93=m -CONFIG_DVB_TUNER_ITD1000=m -CONFIG_DVB_TUNER_CX24113=m -CONFIG_DVB_TDA826X=m -CONFIG_DVB_TUA6100=m -CONFIG_DVB_CX24116=m -CONFIG_DVB_SI21XX=m -CONFIG_DVB_DS3000=m -CONFIG_DVB_SP8870=m -CONFIG_DVB_SP887X=m -CONFIG_DVB_CX22700=m -CONFIG_DVB_CX22702=m -CONFIG_DVB_S5H1432=m -CONFIG_DVB_IX2505V=m -CONFIG_DVB_L64781=m -CONFIG_DVB_NXT6000=m -CONFIG_DVB_MT352=m -CONFIG_DVB_DIB7000M=m -CONFIG_DVB_DIB7000P=m -CONFIG_DVB_TDA10048=m -CONFIG_DVB_VES1820=m -CONFIG_DVB_TDA10021=m -CONFIG_DVB_TDA10023=m -CONFIG_DVB_STV0297=m -CONFIG_DVB_NXT200X=m -CONFIG_DVB_OR51211=m -CONFIG_DVB_OR51132=m -CONFIG_DVB_BCM3510=m -CONFIG_DVB_LGDT330X=m -CONFIG_DVB_LGDT3305=m -CONFIG_DVB_S5H1409=m -CONFIG_DVB_AU8522=m -CONFIG_DVB_S5H1411=m -CONFIG_DVB_DIB8000=m -CONFIG_DVB_TUNER_DIB0070=m -CONFIG_DVB_TUNER_DIB0090=m -CONFIG_DVB_LNBP21=m -CONFIG_DVB_ISL6421=m -CONFIG_DVB_ISL6423=m -CONFIG_DVB_LGS8GXX=m -CONFIG_DVB_ATBM8830=m -CONFIG_DVB_TDA665x=m -CONFIG_DVB_STV0299=m -CONFIG_DVB_MB86A16=m -CONFIG_DVB_DRXD=m -CONFIG_DVB_CXD2820R=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_AF9035=m # -# Supported Frontend Modules +# Supported DVB Modules # CONFIG_DVB_BT8XX=m CONFIG_DVB_BUDGET_CORE=m @@ -2688,19 +2799,14 @@ CONFIG_DVB_USB_ANYSEE=m CONFIG_DVB_USB_DW2102=m CONFIG_DVB_USB_FRIIO=m CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_IT913X=m +CONFIG_DVB_USB_MXL111SF=m CONFIG_DVB_DM1105=m -CONFIG_DVB_DRX397XD=m -CONFIG_DVB_LGDT3304=m -CONFIG_DVB_S921=m -CONFIG_DVB_ISL6405=m -CONFIG_DVB_LGS8GL5=m -CONFIG_DVB_DUMMY_FE=m CONFIG_DVB_FIREDTV=m CONFIG_DVB_NGENE=m -CONFIG_DVB_MB86A20S=m +CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_USB_TECHNISAT_USB2=m -CONFIG_DVB_DIB9000=m -CONFIG_DVB_STV0367=m # # Supported SAA7146 based PCI Adapters @@ -2712,9 +2818,6 @@ CONFIG_DVB_BUDGET_CI=m CONFIG_DVB_BUDGET_AV=m CONFIG_DVB_BUDGET_PATCH=m -# -# Supported USB Adapters -# CONFIG_DVB_TTUSB_BUDGET=m # @@ -2766,14 +2869,20 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y # CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set CONFIG_RC_CORE=m +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m CONFIG_RC_LOOPBACK=m CONFIG_RC_MAP=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m CONFIG_IR_NEC_DECODER=m CONFIG_IR_RC5_DECODER=m CONFIG_IR_RC6_DECODER=m CONFIG_IR_JVC_DECODER=m CONFIG_IR_SONY_DECODER=m CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m CONFIG_IR_LIRC_CODEC=m CONFIG_IR_IMON=m CONFIG_IR_MCEUSB=m @@ -2781,6 +2890,10 @@ CONFIG_IR_ITE_CIR=m CONFIG_IR_NUVOTON=m CONFIG_IR_FINTEK=m CONFIG_IR_REDRAT3=m +CONFIG_IR_ENE=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m +CONFIG_IR_IGUANA=m CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -2799,23 +2912,22 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y # CONFIG_FB_FOREIGN_ENDIAN is not set -CONFIG_FB_3DFX=m -CONFIG_FB_3DFX_ACCEL=y -CONFIG_FB_3DFX_I2C=y +# CONFIG_FB_3DFX is not set # CONFIG_FB_ARC is not set # CONFIG_FB_ARK is not set -CONFIG_FB_ATY128=m -CONFIG_FB_ATY=m -CONFIG_FB_ATY_CT=y -CONFIG_FB_ATY_GX=y -CONFIG_FB_ATY_GENERIC_LCD=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY_CT is not set +# CONFIG_FB_ATY_GX is not set # CONFIG_FB_ASILIANT is not set +# CONFIG_FB_AUO_K190X is not set # CONFIG_FB_CARMINE is not set -CONFIG_FB_CIRRUS=m +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_GEODE is not set # CONFIG_FB_HECUBA is not set # CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set CONFIG_FB_I810=m CONFIG_FB_I810_GTF=y CONFIG_FB_I810_I2C=y @@ -2823,39 +2935,34 @@ CONFIG_FB_I810_I2C=y # CONFIG_FB_INTEL is not set # CONFIG_FB_INTEL_DEBUG is not set # CONFIG_FB_INTEL_I2C is not set -CONFIG_FB_KYRO=m +# CONFIG_FB_KYRO is not set # CONFIG_FB_LE80578 is not set -CONFIG_FB_MATROX=m -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -CONFIG_FB_MATROX_I2C=m -CONFIG_FB_MATROX_MAVEN=m -CONFIG_FB_NEOMAGIC=m -CONFIG_FB_NVIDIA=m +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +# CONFIG_FB_MATROX_G is not set +# CONFIG_FB_MATROX_I2C is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_NVIDIA_I2C is not set # CONFIG_FB_NVIDIA_DEBUG is not set -CONFIG_FB_NVIDIA_I2C=y # CONFIG_FB_PM2 is not set # CONFIG_FB_PM2_FIFO_DISCONNECT is not set # CONFIG_FB_PM3 is not set -CONFIG_FB_RADEON=m +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RADEON_I2C is not set # CONFIG_FB_RADEON_DEBUG is not set -CONFIG_FB_RADEON_I2C=y -CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA is not set # CONFIG_FB_RIVA_DEBUG is not set # CONFIG_FB_RIVA_I2C is not set # CONFIG_FB_S1D13XXX is not set -CONFIG_FB_S3=m -CONFIG_FB_S3_DDC=y -CONFIG_FB_SAVAGE=m -CONFIG_FB_SAVAGE_I2C=y -CONFIG_FB_SAVAGE_ACCEL=y +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set # CONFIG_FB_SIS is not set -CONFIG_FB_SIS_300=y -CONFIG_FB_SIS_315=y -CONFIG_FB_SM501=m +# CONFIG_FB_SM501 is not set +# CONFIG_FB_SMSCUFX is not set CONFIG_FB_TILEBLITTING=y -CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_UVESA is not set CONFIG_FB_VESA=y CONFIG_FB_VGA16=m @@ -2863,17 +2970,14 @@ CONFIG_FB_VIRTUAL=m CONFIG_FB_VOODOO1=m # CONFIG_FB_VT8623 is not set CONFIG_FB_EFI=y -CONFIG_FB_VIA=m -CONFIG_FB_VIA_X_COMPATIBILITY=y +# CONFIG_FB_VIA is not set # CONFIG_FB_VIA_DIRECT_PROCFS is not set -CONFIG_FB_METRONOME=m -CONFIG_FB_MB862XX=m -CONFIG_FB_MB862XX_PCI_GDC=y -CONFIG_FB_MB862XX_LIME=y -CONFIG_FB_MB862XX_I2C=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set # CONFIG_FB_PRE_INIT_FB is not set # CONFIG_FB_TMIO is not set # CONFIG_FB_BROADSHEET is not set +CONFIG_FB_UDL=m # CONFIG_FIRMWARE_EDID is not set @@ -2998,13 +3102,10 @@ CONFIG_SND_HDA_CODEC_CA0110=y CONFIG_SND_HDA_CODEC_ANALOG=y CONFIG_SND_HDA_CODEC_SIGMATEL=y CONFIG_SND_HDA_CODEC_VIA=y -CONFIG_SND_HDA_CODEC_ATIHDMI=y CONFIG_SND_HDA_CODEC_CIRRUS=y CONFIG_SND_HDA_CODEC_CONEXANT=y CONFIG_SND_HDA_CODEC_CMEDIA=y -CONFIG_SND_HDA_CODEC_INTELHDMI=y CONFIG_SND_HDA_CODEC_SI3054=y -CONFIG_SND_HDA_CODEC_NVHDMI=y CONFIG_SND_HDA_CODEC_HDMI=y CONFIG_SND_HDA_CODEC_CA0132=y CONFIG_SND_HDA_GENERIC=y @@ -3013,7 +3114,6 @@ CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 CONFIG_SND_HDA_RECONFIG=y CONFIG_SND_HDA_PREALLOC_SIZE=4096 CONFIG_SND_HDSPM=m -CONFIG_SND_HIFIER=m CONFIG_SND_ICE1712=m CONFIG_SND_ICE1724=m CONFIG_SND_INTEL8X0=y @@ -3059,9 +3159,7 @@ CONFIG_SND_USB_6FIRE=m # # PCMCIA devices # -CONFIG_SND_PCMCIA=y -CONFIG_SND_VXPOCKET=m -CONFIG_SND_PDAUDIOCF=m +# CONFIG_SND_PCMCIA is not set CONFIG_SND_FIREWIRE=y CONFIG_SND_FIREWIRE_SPEAKERS=m @@ -3096,14 +3194,17 @@ CONFIG_USB_SUSPEND=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHCI_MV is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_OHCI_HCD=y # CONFIG_USB_OHCI_HCD_SSB is not set +# CONFIG_USB_OHCI_HCD_PLATFORM is not set CONFIG_USB_UHCI_HCD=y CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_HCD_ISO=y # CONFIG_USB_SL811_CS is not set # CONFIG_USB_R8A66597_HCD is not set -CONFIG_USB_XHCI_HCD=m +CONFIG_USB_XHCI_HCD=y # CONFIG_USB_XHCI_HCD_DEBUGGING is not set CONFIG_USB_ISP1362_HCD=m @@ -3133,9 +3234,10 @@ CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_ALAUDA=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_REALTEK=m +CONFIG_REALTEK_AUTOPM=y CONFIG_USB_STORAGE_ENE_UB6250=m # CONFIG_USB_LIBUSUAL is not set -CONFIG_USB_UAS=m +# CONFIG_USB_UAS is not set # @@ -3145,11 +3247,14 @@ CONFIG_USB_HID=y CONFIG_HID_SUPPORT=y -CONFIG_HID=m +CONFIG_HID=ym +CONFIG_HID_BATTERY_STRENGTH=y # debugging default is y upstream now CONFIG_HIDRAW=y +CONFIG_UHID=m CONFIG_HID_PID=y CONFIG_LOGITECH_FF=y +CONFIG_HID_LOGITECH_DJ=m CONFIG_LOGIWII_FF=y CONFIG_LOGIRUMBLEPAD2_FF=y CONFIG_PANTHERLORD_FF=y @@ -3162,18 +3267,15 @@ CONFIG_USB_IDMOUSE=m CONFIG_DRAGONRISE_FF=y CONFIG_GREENASIA_FF=y CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_3M_PCT=y CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MOSART=y CONFIG_HID_MULTITOUCH=m CONFIG_HID_NTRIG=y CONFIG_HID_QUANTA=y -CONFIG_HID_STANTUM=y -CONFIG_HID_CANDO=m +CONFIG_HID_PRIMAX=m CONFIG_HID_PRODIKEYS=m CONFIG_HID_DRAGONRISE=m -CONFIG_HID_EGALAX=m CONFIG_HID_GYRATION=m CONFIG_HID_TWINHAN=m CONFIG_HID_ORTEK=m @@ -3181,6 +3283,7 @@ CONFIG_HID_PANTHERLORD=m CONFIG_HID_PETALYNX=m CONFIG_HID_PICOLCD=m CONFIG_HID_ROCCAT=m +CONFIG_HID_ROCCAT_ISKU=m CONFIG_HID_ROCCAT_KONE=m CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m @@ -3191,7 +3294,6 @@ CONFIG_HID_TOPSEED=m CONFIG_HID_THRUSTMASTER=m CONFIG_HID_ZEROPLUS=m CONFIG_HID_ZYDACRON=m -CONFIG_HID_ACRUX_FF=m CONFIG_HID_EMS_FF=m CONFIG_HID_ELECOM=m CONFIG_HID_UCLOGIC=m @@ -3199,14 +3301,23 @@ CONFIG_HID_WALTOP=m CONFIG_HID_ROCCAT_PYRA=m CONFIG_HID_ROCCAT_KONEPLUS=m CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y CONFIG_HID_KEYTOUCH=m CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO_TPKBD=m CONFIG_HID_ROCCAT_ARVO=m CONFIG_HID_ROCCAT_KOVAPLUS=m CONFIG_HID_HOLTEK=m CONFIG_HOLTEK_FF=y CONFIG_HID_SPEEDLINK=m CONFIG_HID_WIIMOTE=m +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_KYE=m +CONFIG_HID_SAITEK=m +CONFIG_HID_TIVO=m +CONFIG_HID_GENERIC=y +CONFIG_HID_AUREAL=m + # # USB Imaging devices @@ -3217,10 +3328,7 @@ CONFIG_USB_MICROTEK=m # # USB Multimedia devices # -CONFIG_DAB=y -CONFIG_USB_DABUSB=m -CONFIG_USB_VICAM=m CONFIG_USB_DSBR=m # CONFIG_USB_ET61X251 is not set CONFIG_USB_M5602=m @@ -3240,7 +3348,6 @@ CONFIG_USB_GSPCA_PAC207=m CONFIG_USB_GSPCA_PAC7311=m CONFIG_USB_GSPCA_SN9C2028=m CONFIG_USB_GSPCA_SN9C20X=m -CONFIG_USB_GSPCA_SN9C20X_EVDEV=y CONFIG_USB_GSPCA_SONIXB=m CONFIG_USB_GSPCA_SONIXJ=m CONFIG_USB_GSPCA_SPCA500=m @@ -3252,6 +3359,7 @@ CONFIG_USB_GSPCA_SPCA561=m CONFIG_USB_GSPCA_STK014=m CONFIG_USB_GSPCA_SUNPLUS=m CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m CONFIG_USB_GSPCA_TV8532=m CONFIG_USB_GSPCA_VC032X=m CONFIG_USB_GSPCA_ZC3XX=m @@ -3261,6 +3369,7 @@ CONFIG_USB_GSPCA_PAC7302=m CONFIG_USB_GSPCA_STV0680=m CONFIG_USB_GL860=m CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m CONFIG_USB_GSPCA_KONICA=m CONFIG_USB_GSPCA_XIRLINK_CIT=m CONFIG_USB_GSPCA_SPCA1528=m @@ -3268,32 +3377,14 @@ CONFIG_USB_GSPCA_SQ930X=m CONFIG_USB_GSPCA_NW80X=m CONFIG_USB_GSPCA_VICAM=m CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_SE401=m -CONFIG_USB_IBMCAM=m -CONFIG_USB_KONICAWC=m -# CONFIG_USB_OV511 is not set CONFIG_USB_S2255=m -CONFIG_USB_SE401=m # CONFIG_VIDEO_SH_MOBILE_CEU is not set # CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -# CONFIG_USB_STV680 is not set # CONFIG_USB_SN9C102 is not set CONFIG_USB_ZR364XX=m -CONFIG_SOC_CAMERA=m -CONFIG_SOC_CAMERA_MT9M001=m -CONFIG_SOC_CAMERA_MT9V022=m -CONFIG_SOC_CAMERA_PLATFORM=m -CONFIG_SOC_CAMERA_MT9M111=m -CONFIG_SOC_CAMERA_MT9T031=m -CONFIG_SOC_CAMERA_TW9910=m -CONFIG_SOC_CAMERA_OV772X=m -CONFIG_SOC_CAMERA_MT9T112=m -CONFIG_SOC_CAMERA_RJ54N1=m -CONFIG_SOC_CAMERA_OV9640=m -CONFIG_SOC_CAMERA_OV6650=m -CONFIG_SOC_CAMERA_IMX074=m -CONFIG_SOC_CAMERA_OV2640=m -CONFIG_SOC_CAMERA_OV9740=m +# CONFIG_SOC_CAMERA is not set # # USB Network adaptors @@ -3338,6 +3429,7 @@ CONFIG_USB_EPSON2888=y CONFIG_USB_KC2190=y # CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_CHIPIDEA is not set # # USB port drivers @@ -3362,6 +3454,7 @@ CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_EDGEPORT=m CONFIG_USB_SERIAL_EDGEPORT_TI=m CONFIG_USB_SERIAL_EMPEG=m +# CONFIG_USB_SERIAL_F81232 is not set CONFIG_USB_SERIAL_FTDI_SIO=m CONFIG_USB_SERIAL_FUNSOFT=m CONFIG_USB_SERIAL_GARMIN=m @@ -3387,17 +3480,19 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m +# CONFIG_USB_SERIAL_METRO is not set CONFIG_USB_SERIAL_MOS7720=m CONFIG_USB_SERIAL_MOS7715_PARPORT=y # CONFIG_USB_SERIAL_ZIO is not set CONFIG_USB_SERIAL_MOS7840=m CONFIG_USB_SERIAL_MOTOROLA=m CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_SERIAL_OTI6858=m CONFIG_USB_SERIAL_OPTICON=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_QUATECH2 is not set CONFIG_USB_SERIAL_SAFE=m CONFIG_USB_SERIAL_SAFE_PADDED=y CONFIG_USB_SERIAL_SIERRAWIRELESS=m @@ -3411,7 +3506,7 @@ CONFIG_USB_SERIAL_QCAUX=m CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m CONFIG_USB_SERIAL_DEBUG=m CONFIG_USB_SERIAL_SSU100=m -CONFIG_USB_SERIAL_SAMBA=m +CONFIG_USB_SERIAL_QT2=m CONFIG_USB_SERIAL_CONSOLE=y @@ -3430,7 +3525,6 @@ CONFIG_USB_SEVSEG=m CONFIG_USB_ALI_M5632=y CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_ATM=m -CONFIG_USB_BERRY_CHARGE=m CONFIG_USB_CXACRU=m # CONFIG_USB_C67X00_HCD is not set # CONFIG_USB_CYTHERM is not set @@ -3440,7 +3534,7 @@ CONFIG_USB_FTDI_ELAN=m CONFIG_USB_FILE_STORAGE=m # CONFIG_USB_FILE_STORAGE_TEST is not set # CONFIG_USB_GADGET is not set -# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_DWC3 is not set # CONFIG_USB_GADGETFS is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_ISP1760_HCD is not set @@ -3448,7 +3542,6 @@ CONFIG_USB_FILE_STORAGE=m CONFIG_USB_IOWARRIOR=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m -CONFIG_USB_VST=m CONFIG_USB_LCD=m CONFIG_USB_LD=m CONFIG_USB_LEGOTOWER=m @@ -3457,7 +3550,6 @@ CONFIG_USB_PWC=m CONFIG_USB_PWC_INPUT_EVDEV=y # CONFIG_USB_PWC_DEBUG is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_QUICKCAM_MESSENGER is not set CONFIG_USB_SISUSBVGA=m CONFIG_USB_SISUSBVGA_CON=y CONFIG_RADIO_SI470X=y @@ -3472,11 +3564,12 @@ CONFIG_USB_TRANCEVIBRATOR=m CONFIG_USB_U132_HCD=m CONFIG_USB_UEAGLEATM=m CONFIG_USB_XUSBATM=m -# CONFIG_USB_ZC0301 is not set CONFIG_USB_ZERO=m CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +# CONFIG_USB_ISP1301 is not set + # CONFIG_USB_OTG is not set # @@ -3515,6 +3608,7 @@ CONFIG_MFD_WM8400=m # CONFIG_MFD_WM8994 is not set # CONFIG_MFD_88PM860X is not set # CONFIG_LPC_SCH is not set +# CONFIG_LPC_ICH is not set # CONFIG_HTC_I2CPLD is not set # CONFIG_MFD_MAX8925 is not set # CONFIG_MFD_ASIC3 is not set @@ -3524,7 +3618,17 @@ CONFIG_MFD_WM8400=m # CONFIG_MFD_RDC321X is not set # CONFIG_MFD_JANZ_CMODIO is not set # CONFIG_MFD_WM831X_I2C is not set -CONFIG_MFD_CS5535=m +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_ARIZONA is not set +# CONFIG_MFD_ARIZONA_I2C is not set # # File systems @@ -3567,16 +3671,16 @@ CONFIG_QFMT_V2=y CONFIG_QUOTACTL=y CONFIG_DNOTIFY=y # Autofsv3 is obsolete. -# CONFIG_AUTOFS_FS is not set # systemd is dependant upon AUTOFS, so build it in. CONFIG_AUTOFS4_FS=y -CONFIG_EXOFS_FS=m +# CONFIG_EXOFS_FS is not set # CONFIG_EXOFS_DEBUG is not set -CONFIG_NILFS2_FS=m -CONFIG_LOGFS=m +# CONFIG_NILFS2_FS is not set +# CONFIG_LOGFS is not set CONFIG_CEPH_FS=m CONFIG_BLK_DEV_RBD=m CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set CONFIG_FSCACHE=m CONFIG_FSCACHE_STATS=y @@ -3629,26 +3733,22 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_BEFS_FS=m # CONFIG_BEFS_DEBUG is not set -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_JFFS2_FS=m -CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set -CONFIG_JFFS2_FS_WRITEBUFFER=y -# CONFIG_JFFS2_FS_WBUF_VERIFY is not set -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_FS_XATTR=y -CONFIG_JFFS2_FS_POSIX_ACL=y -CONFIG_JFFS2_FS_SECURITY=y +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set + CONFIG_CRAMFS=m CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZLIB=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set # CONFIG_SQUASHFS_EMBEDDED is not set -CONFIG_VXFS_FS=m +# CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set CONFIG_SYSV_FS=m CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set @@ -3657,7 +3757,7 @@ CONFIG_9P_FS=m CONFIG_9P_FSCACHE=y CONFIG_9P_FS_POSIX_ACL=y CONFIG_FUSE_FS=m -CONFIG_OMFS_FS=m +# CONFIG_OMFS_FS is not set CONFIG_CUSE=m # @@ -3665,33 +3765,34 @@ CONFIG_CUSE=m # CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m +CONFIG_NFS_V2=y CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +# CONFIG_NFS_SWAP is not set CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y +# CONFIG_NFSD_FAULT_INJECTION is not set CONFIG_NFS_FSCACHE=y # CONFIG_NFS_USE_LEGACY_DNS is not set # CONFIG_NFS_USE_NEW_IDMAPPER is not set -# CONFIG_NFSD_DEPRECATED is not set CONFIG_PNFS_OBJLAYOUT=m +CONFIG_PNFS_BLOCK=m CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUNRPC_DEBUG=y CONFIG_RPCSEC_GSS_KRB5=m -CONFIG_RPCSEC_GSS_SPKM3=m -# CONFIG_SMB_FS is not set -# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m CONFIG_CIFS_STATS=y # CONFIG_CIFS_STATS2 is not set -CONFIG_CIFS_EXPERIMENTAL=y CONFIG_CIFS_UPCALL=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y @@ -3723,18 +3824,16 @@ CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m CONFIG_BTRFS_FS=m CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set -CONFIG_CONFIGFS_FS=m +CONFIG_CONFIGFS_FS=y CONFIG_DLM=m CONFIG_DLM_DEBUG=y CONFIG_GFS2_FS=m CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_UBIFS_FS=m -CONFIG_UBIFS_FS_XATTR=y -# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_UBIFS_FS is not set # # Partition Types @@ -3800,6 +3899,17 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m CONFIG_NLS_UTF8=m CONFIG_NLS_ASCII=y @@ -3818,27 +3928,74 @@ CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_INFO=y CONFIG_FRAME_POINTER=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_DEBUG_DRIVER is not set CONFIG_HEADERS_CHECK=y -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_TRACE is not set # CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_READABLE_ASM is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_LOCKDEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# DEBUG options that don't get enabled/disabled with 'make debug/release' +# +# Kmemleak still produces a lot of false positives. +# CONFIG_DEBUG_KMEMLEAK is not set +# +# This generates a huge amount of dmesg spew +# CONFIG_DEBUG_KOBJECT is not set +# +# +# These debug options are deliberatly left on (even in 'make release' kernels). +# They aren't that much of a performance impact, and the value +# from getting useful bug-reports makes it worth leaving them on. +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DEBUG_DEVRES=y +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_NX_TEST=m +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_ATOMIC64_SELFTEST=y +CONFIG_MEMORY_FAILURE=y +CONFIG_HWPOISON_INJECT=m +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_LATENCYTOP=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRASH is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_RAMOOPS is not set + CONFIG_KGDB=y CONFIG_KGDB_SERIAL_CONSOLE=y CONFIG_KGDB_TESTS=y CONFIG_KGDB_LOW_LEVEL_TRAP=y # CONFIG_KGDB_TESTS_ON_BOOT is not set + # # Security options # CONFIG_SECURITY=y +CONFIG_SECURITYFS=y # CONFIG_SECURITY_DMESG_RESTRICT is not set CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_NETWORK_XFRM=y @@ -3850,11 +4007,14 @@ CONFIG_SECURITY_SELINUX_DEVELOP=y CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1 CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 CONFIG_SECURITY_SELINUX_AVC_STATS=y +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set # CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set # # Cryptographic options @@ -3924,6 +4084,9 @@ CONFIG_CRYPTO_ANSI_CPRNG=m CONFIG_CRYPTO_DEV_HIFN_795X=m CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_USER=m + + # Random number generation @@ -3932,11 +4095,14 @@ CONFIG_CRYPTO_PCRYPT=m # CONFIG_CRC16=y CONFIG_CRC32=m +# CONFIG_CRC32_SELFTEST is not set CONFIG_CRC_CCITT=m CONFIG_CRC_ITU_T=m CONFIG_CRC_T10DIF=m CONFIG_CRC8=m +# CONFIG_CRC7 is not set CONFIG_CORDIC=m +# CONFIG_DDR is not set CONFIG_CRYPTO_ZLIB=m CONFIG_ZLIB_INFLATE=y @@ -3965,6 +4131,7 @@ CONFIG_FB_ATY128_BACKLIGHT=y CONFIG_FB_ATY_BACKLIGHT=y # CONFIG_BACKLIGHT_SAHARA is not set CONFIG_BACKLIGHT_WM831X=m +CONFIG_BACKLIGHT_LP855X=m CONFIG_LCD_CLASS_DEVICE=m CONFIG_LCD_PLATFORM=m @@ -3972,8 +4139,8 @@ CONFIG_LCD_PLATFORM=m CONFIG_SCHEDSTATS=y CONFIG_SCHED_DEBUG=y CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y CONFIG_SCHED_OMIT_FRAME_POINTER=y -CONFIG_GROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_AUTOGROUP=y @@ -3982,17 +4149,17 @@ CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set -CONFIG_CGROUP_NS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y -CONFIG_CGROUP_MEM_RES_CTLR=y -CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y # XXX disabled by default, pass 'swapaccount' -# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y # XXX disabled by default, pass 'swapaccount' +# CONFIG_MEMCG_SWAP_ENABLED is not set +CONFIG_MEMCG_KMEM=y +# CONFIG_CGROUP_HUGETLB is not set CONFIG_CGROUP_PERF=y CONFIG_BLK_CGROUP=y -# CONFIG_DEBUG_BLK_CGROUP is not set # CONFIG_SYSFS_DEPRECATED is not set # CONFIG_SYSFS_DEPRECATED_V2 is not set @@ -4007,6 +4174,8 @@ CONFIG_KEXEC=y CONFIG_HWMON=y # CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_THERMAL_HWMON=y + CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -4017,12 +4186,14 @@ CONFIG_IBMASR=m CONFIG_PM_DEBUG=y CONFIG_PM_TRACE=y -# CONFIG_PM_VERBOSE is not set -CONFIG_PM_TEST_SUSPEND=y +CONFIG_PM_TRACE_RTC=y +# CONFIG_PM_TEST_SUSPEND is not set CONFIG_PM_RUNTIME=y +# CONFIG_PM_OPP is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -4041,58 +4212,26 @@ CONFIG_I82365=m # CONFIG_LTPC is not set # CONFIG_COPS is not set -CONFIG_SCSI_AHA152X=m -CONFIG_SCSI_AHA1542=m -# CONFIG_SCSI_IN2000 is not set -CONFIG_SCSI_ARCMSR=m -CONFIG_SCSI_ARCMSR_AER=y -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_EL1 is not set # CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set CONFIG_EL3=m # CONFIG_3C515 is not set -# CONFIG_LANCE is not set CONFIG_NET_VENDOR_SMC=y # CONFIG_WD80x3 is not set CONFIG_ULTRA=m -# CONFIG_SMC9194 is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NI52 is not set # CONFIG_NI65 is not set -# CONFIG_AT1700 is not set # CONFIG_DEPCA is not set CONFIG_NET_ISA=y CONFIG_NE2000=m # CONFIG_E2100 is not set -CONFIG_EWRK3=m -# CONFIG_EEXPRESS is not set -# CONFIG_EEXPRESS_PRO is not set # CONFIG_HPLAN_PLUS is not set # CONFIG_HPLAN is not set -# CONFIG_LP486E is not set -# CONFIG_ETH16I is not set -# CONFIG_ZNET is not set -# CONFIG_SEEQ8005 is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set # CONFIG_IBMTR is not set # CONFIG_SKISA is not set # CONFIG_PROTEON is not set # CONFIG_SMCTR is not set -# CONFIG_WAVELAN is not set # CONFIG_HISAX_16_0 is not set # CONFIG_HISAX_AVM_A1 is not set # CONFIG_HISAX_IX1MICROR2 is not set @@ -4121,31 +4260,26 @@ CONFIG_EWRK3=m # CONFIG_SERIAL_8250_HUB6 is not set # CONFIG_SERIAL_8250_EXAR_ST16C554 is not set -# CONFIG_PCWATCHDOG is not set -# CONFIG_WDT is not set - -# CONFIG_VIDEO_PMS is not set CONFIG_RADIO_ADAPTERS=y -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_SF16FMR2 is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TEA5764 is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set -# CONFIG_RADIO_SAA7706H is not set +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_ZOLTRIX=m # CONFIG_SND_OPL4_LIB is not set # CONFIG_SND_AD1816A is not set # CONFIG_SND_AD1848 is not set # CONFIG_SND_CS4231 is not set CONFIG_SND_CS4236=m -# CONFIG_SND_ES968 is not set # CONFIG_SND_ES1688 is not set # CONFIG_SND_ES18XX is not set # CONFIG_SND_GUSCLASSIC is not set @@ -4164,9 +4298,7 @@ CONFIG_SND_SBAWE=m # CONFIG_SND_ALS100 is not set # CONFIG_SND_AZT2320 is not set # CONFIG_SND_CMI8330 is not set -# CONFIG_SND_DT019X is not set CONFIG_SND_OPL3SA2=m -# CONFIG_SND_SGALAXY is not set # CONFIG_SND_SSCAPE is not set CONFIG_SND_DARLA20=m CONFIG_SND_GINA20=m @@ -4193,34 +4325,42 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_AMS_DELTA is not set # CONFIG_LEDS_LOCOMO is not set # CONFIG_LEDS_NET48XX is not set +# CONFIG_LEDS_NET5501 is not set # CONFIG_LEDS_PCA9532 is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_S3C24XX is not set +# CONFIG_LEDS_PCA9633 is not set CONFIG_LEDS_DELL_NETBOOKS=m +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m CONFIG_LEDS_TRIGGER_IDE_DISK=y CONFIG_LEDS_TRIGGER_HEARTBEAT=m CONFIG_LEDS_TRIGGER_BACKLIGHT=m CONFIG_LEDS_TRIGGER_DEFAULT_ON=m +CONFIG_LEDS_TRIGGER_TRANSIENT=m CONFIG_LEDS_ALIX2=m -CONFIG_LEDS_WM8350=m -CONFIG_LEDS_LP3944=m -CONFIG_LEDS_WM831X_STATUS=m -CONFIG_LEDS_REGULATOR=m -CONFIG_LEDS_LT3593=m -CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_CLEVO_MAIL=m CONFIG_LEDS_INTEL_SS4200=m +CONFIG_LEDS_LM3530=m +CONFIG_LEDS_LM3556=m +CONFIG_LEDS_BLINKM=m +CONFIG_LEDS_LP3944=m CONFIG_LEDS_LP5521=m CONFIG_LEDS_LP5523=m -CONFIG_LEDS_LM3530=m +CONFIG_LEDS_LT3593=m +CONFIG_LEDS_REGULATOR=m +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_WM8350=m +CONFIG_LEDS_WM831X_STATUS=m CONFIG_DMADEVICES=y CONFIG_DMA_ENGINE=y CONFIG_DW_DMAC=m # CONFIG_TIMB_DMA is not set -CONFIG_NET_DMA=y # CONFIG_DMATEST is not set CONFIG_ASYNC_TX_DMA=y @@ -4233,9 +4373,7 @@ CONFIG_DYNAMIC_FTRACE=y # CONFIG_IRQSOFF_TRACER is not set CONFIG_SCHED_TRACER=y CONFIG_CONTEXT_SWITCH_TRACER=y -CONFIG_WORKQUEUE_TRACER=y CONFIG_FTRACE_SYSCALLS=y -CONFIG_KMEMTRACE=y CONFIG_FTRACE_MCOUNT_RECORD=y # CONFIG_FTRACE_STARTUP_TEST is not set # CONFIG_TRACE_BRANCH_PROFILING is not set @@ -4243,12 +4381,15 @@ CONFIG_FUNCTION_PROFILER=y CONFIG_RING_BUFFER_BENCHMARK=m CONFIG_FUNCTION_TRACER=y CONFIG_STACK_TRACER=y +# CONFIG_FUNCTION_GRAPH_TRACER is not set CONFIG_KPROBES=y +CONFIG_KPROBE_EVENT=y +CONFIG_UPROBE_EVENT=y +# CONFIG_KPROBES_SANITY_TEST is not set +CONFIG_JUMP_LABEL=y CONFIG_OPTPROBES=y -# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set - CONFIG_HZ_1000=y CONFIG_TIMER_STATS=y @@ -4261,30 +4402,37 @@ CONFIG_CFAG12864B=y CONFIG_CFAG12864B_RATE=20 # CONFIG_PHANTOM is not set +# CONFIG_INTEL_MID_PTI is not set -CONFIG_POWER_SUPPLY=m +CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set + # CONFIG_TEST_POWER is not set CONFIG_APM_POWER=m # CONFIG_WM831X_POWER is not set + # CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2781 is not set # CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set # CONFIG_BATTERY_BQ20Z75 is not set # CONFIG_BATTERY_DS2780 is not set -# CONFIG_CHARGER_ISP1704 is not set -# CONFIG_CHARGER_MAX8903 is not set # CONFIG_BATTERY_BQ27x00 is not set # CONFIG_BATTERY_MAX17040 is not set -# CONFIG_PDA_POWER is not set -# CONFIG_CHARGER_GPIO is not set # CONFIG_BATTERY_MAX17042 is not set + +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set # CONFIG_CHARGER_PCF50633 is not set +# CONFIG_PDA_POWER is not set + CONFIG_AUXDISPLAY=y CONFIG_UIO=m CONFIG_UIO_CIF=m -CONFIG_UIO_SMX=m # CONFIG_UIO_PDRV is not set # CONFIG_UIO_PDRV_GENIRQ is not set CONFIG_UIO_AEC=m @@ -4292,57 +4440,36 @@ CONFIG_UIO_SERCOS3=m CONFIG_UIO_PCI_GENERIC=m # CONFIG_UIO_NETX is not set -# CONFIG_CRC7 is not set - +# CONFIG_VFIO is not set # LIRC CONFIG_LIRC_STAGING=y CONFIG_LIRC_BT829=m -CONFIG_LIRC_ENE0100=m -CONFIG_LIRC_I2C=m CONFIG_LIRC_IGORPLUGUSB=m CONFIG_LIRC_IMON=m -CONFIG_LIRC_IT87=m -CONFIG_LIRC_ITE8709=m -CONFIG_LIRC_MCEUSB=m CONFIG_LIRC_ZILOG=m CONFIG_LIRC_PARALLEL=m CONFIG_LIRC_SERIAL=m CONFIG_LIRC_SERIAL_TRANSMITTER=y CONFIG_LIRC_SASEM=m CONFIG_LIRC_SIR=m -CONFIG_LIRC_STREAMZAP=m CONFIG_LIRC_TTUSBIR=m # CONFIG_SAMPLES is not set # CONFIG_DEVKMEM is not set -CONFIG_PM_TRACE_RTC=y -CONFIG_R6040=m - CONFIG_BNX2X=m CONFIG_SCSI_BNX2X_FCOE=m CONFIG_NOZOMI=m # CONFIG_TPS65010 is not set -# CONFIG_DEBUG_SECTION_MISMATCH is not set -# CONFIG_KPROBES_SANITY_TEST is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -CONFIG_LATENCYTOP=y -CONFIG_RESOURCE_COUNTERS=y -# CONFIG_COMPAT_BRK is not set - -#FIXME: x86 generic? -CONFIG_LEDS_CLEVO_MAIL=m -CONFIG_I8K=m CONFIG_INPUT_APANEL=m # CONFIG_INTEL_MENLOW is not set CONFIG_ENCLOSURE_SERVICES=m CONFIG_IPWIRELESS=m -CONFIG_RTC_DRV_DS1511=m # CONFIG_BLK_DEV_XIP is not set CONFIG_MEMSTICK=m @@ -4360,42 +4487,26 @@ CONFIG_A11Y_BRAILLE_CONSOLE=y # MT9V022_PCA9536_SWITCH is not set -CONFIG_THERMAL_HWMON=y - CONFIG_OPTIMIZE_INLINING=y # FIXME: This should be x86/ia64 only # CONFIG_HP_ILO is not set # CONFIG_GPIOLIB is not set +# CONFIG_PINCTRL is not set +CONFIG_NET_DSA=m +CONFIG_NET_DSA_MV88E6060=m +CONFIG_NET_DSA_MV88E6131=m +CONFIG_NET_DSA_MV88E6123_61_65=m -CONFIG_NETFILTER_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set -CONFIG_NETFILTER_XT_MATCH_SOCKET=m +# Used by Maemo, we don't care. +# CONFIG_PHONET is not set -# CONFIG_IP_VS_IPV6 is not set +# CONFIG_ICS932S401 is not set -CONFIG_NET_DSA=y -CONFIG_NET_DSA_MV88E6060=y -CONFIG_NET_DSA_MV88E6131=y -CONFIG_NET_DSA_MV88E6123_61_65=y - -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_ACT_SKBEDIT=m - -CONFIG_PHONET=m -# CONFIG_PHONET_PIPECTRLR is not set - -CONFIG_ICS932S401=m # CONFIG_C2PORT is not set - -CONFIG_IT87_WDT=m -CONFIG_W83697UG_WDT=m - # CONFIG_REGULATOR is not set # CONFIG_REGULATOR_DEBUG is not set @@ -4408,48 +4519,39 @@ CONFIG_USB_WUSB_CBAF=m # CONFIG_USB_WUSB_CBAF_DEBUG is not set CONFIG_USB_WHCI_HCD=m CONFIG_USB_HWA_HCD=m +# CONFIG_USB_HCD_BCMA is not set +# CONFIG_USB_HCD_SSB is not set CONFIG_UWB=m CONFIG_UWB_HWA=m CONFIG_UWB_WHCI=m -CONFIG_UWB_WLP=m CONFIG_UWB_I1480U=m -CONFIG_UWB_I1480U_WLP=m CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set +# CONFIG_RTLLIB is not set +# CONFIG_ANDROID is not set +CONFIG_STAGING_MEDIA=y +# CONFIG_DVB_AS102 is not set # CONFIG_ET131X is not set # CONFIG_SLICOSS is not set -# CONFIG_VIDEO_TM6000 is not set # CONFIG_WLAGS49_H2 is not set # CONFIG_WLAGS49_H25 is not set # CONFIG_VIDEO_DT3155 is not set # CONFIG_TI_ST is not set -# CONFIG_ST_BT is not set # CONFIG_FB_XGI is not set # CONFIG_VIDEO_GO7007 is not set -# CONFIG_USB_IP_COMMON is not set # CONFIG_DT3155 is not set # CONFIG_W35UND is not set # CONFIG_PRISM2_USB is not set # CONFIG_ECHO is not set CONFIG_USB_ATMEL=m -# CONFIG_POCH is not set -# CONFIG_OTUS is not set -# CONFIG_RT2860 is not set -# CONFIG_RT2870 is not set # CONFIG_COMEDI is not set # CONFIG_ASUS_OLED is not set # CONFIG_PANEL is not set -# CONFIG_ALTERA_PCIE_CHDMA is not set -# CONFIG_INPUT_MIMIO is not set # CONFIG_TRANZPORT is not set # CONFIG_POHMELFS is not set -# CONFIG_B3DFG is not set # CONFIG_IDE_PHISON is not set -# CONFIG_PLAN9AUTH is not set # CONFIG_LINE6_USB is not set -# CONFIG_RTL8192SU is not set # CONFIG_IIO is not set # CONFIG_VME_BUS is not set # CONFIG_RAR_REGISTER is not set @@ -4458,10 +4560,8 @@ CONFIG_USB_ATMEL=m # CONFIG_RTL8192E is not set # CONFIG_INPUT_GPIO is not set # CONFIG_VIDEO_CX25821 is not set -# CONFIG_HYPERV is not set # CONFIG_R8187SE is not set # CONFIG_RTL8192U is not set -# CONFIG_RAMZSWAP is not set # CONFIG_BATMAN_ADV is not set # CONFIG_FB_SM7XX is not set # CONFIG_SPECTRA is not set @@ -4469,8 +4569,8 @@ CONFIG_USB_ATMEL=m # CONFIG_EASYCAP is not set # CONFIG_SOLO6X10 is not set # CONFIG_ACPI_QUICKSTART is not set -# CONFIG_BRCM80211 is not set -# CONFIG_R8712U is not set +CONFIG_R8712U=m # Larry Finger maintains this (rhbz 699618) +# CONFIG_R8712_AP is not set # CONFIG_ATH6K_LEGACY is not set # CONFIG_USB_ENESTORAGE is not set # CONFIG_BCM_WIMAX is not set @@ -4480,58 +4580,49 @@ CONFIG_USB_ATMEL=m # CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set # CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set # CONFIG_RTS_PSTOR is not set -# CONFIG_DRM_PSB is not set -# CONFIG_ALTERA_STAPL is not set +CONFIG_ALTERA_STAPL=m # CONFIG_DVB_CXD2099 is not set # CONFIG_USBIP_CORE is not set -# CONFIG_BRCMSMAC is not set -# CONFIG_BRCMFMAC is not set # CONFIG_INTEL_MEI is not set # CONFIG_ZCACHE is not set - -# -# Android +# CONFIG_RTS5139 is not set +# CONFIG_NVEC_LEDS is not set +# CONFIG_VT6655 is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_RAMSTER is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_CSR_WIFI is not set # +# END OF STAGING -# CONFIG_DEBUG_VIRTUAL is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -# CONFIG_FUNCTION_GRAPH_TRACER is not set -CONFIG_BOOT_TRACER=y -CONFIG_EARLY_PRINTK_DBGP=y - -CONFIG_SECURITYFS=y - -CONFIG_SCSI_CXGB3_ISCSI=m CONFIG_LIBFC=m CONFIG_LIBFCOE=m CONFIG_FCOE=m CONFIG_FCOE_FNIC=m -# CONFIG_SCSI_LPFC_DEBUG_FS is not set CONFIG_NOP_USB_XCEIV=m -CONFIG_IMA=y +# CONFIG_IMA is not set CONFIG_IMA_MEASURE_PCR_IDX=10 CONFIG_IMA_AUDIT=y CONFIG_IMA_LSM_RULES=y +# CONFIG_EVM is not set +# CONFIG_PWM is not set + CONFIG_LSM_MMAP_MIN_ADDR=65536 -# CONFIG_PAGE_POISONING is not set - -CONFIG_SLOW_WORK=y -CONFIG_SLOW_WORK_DEBUG=y - -# CONFIG_CRASH_DUMP is not set -# CONFIG_CRASH is not set - CONFIG_STRIP_ASM_SYMS=y # CONFIG_RCU_FANOUT_EXACT is not set -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_SRCU_SYNCHRONIZE_DELAY=10 +# CONFIG_RCU_FAST_NO_HZ is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +CONFIG_SPARSE_RCU_POINTER=y CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 @@ -4541,10 +4632,15 @@ CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_IEEE802154=m +CONFIG_IEEE802154_6LOWPAN=m CONFIG_IEEE802154_DRIVERS=m CONFIG_IEEE802154_FAKEHARD=m +CONFIG_IEEE802154_FAKELB=m -# CONFIG_GCOV_KERNEL is not set +CONFIG_MAC802154=m + +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set CONFIG_PPS=m # CONFIG_PPS_CLIENT_KTIMER is not set @@ -4552,55 +4648,21 @@ CONFIG_PPS_CLIENT_LDISC=m # CONFIG_PPS_DEBUG is not set CONFIG_PPS_CLIENT_PARPORT=m CONFIG_PPS_GENERATOR_PARPORT=m +CONFIG_PPS_CLIENT_GPIO=m CONFIG_NTP_PPS=y CONFIG_PTP_1588_CLOCK=m +CONFIG_PTP_1588_CLOCK_PCH=m -# CONFIG_USB_SERIAL_QUATECH2 is not set -# CONFIG_VT6655 is not set -CONFIG_FB_UDL=m - -# DEBUG options that don't get enabled/disabled with 'make debug/release' -# -# Kmemleak still produces a lot of false positives. -# CONFIG_DEBUG_KMEMLEAK is not set -# -# This generates a huge amount of dmesg spew -# CONFIG_DEBUG_KOBJECT is not set -# -# -# These debug options are deliberatly left on (even in 'make release' kernels). -# They aren't that much of a performance impact, and the value -# from getting useful bug-reports makes it worth leaving them on. -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -CONFIG_BOOT_PRINTK_DELAY=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_SHIRQ=y -CONFIG_DEBUG_DEVRES=y -CONFIG_DEBUG_RODATA_TEST=y -CONFIG_DEBUG_NX_TEST=m -CONFIG_DEBUG_BOOT_PARAMS=y -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_LOCKUP_DETECTOR=y -# CONFIG_DEBUG_INFO_REDUCED is not set -# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set -# CONFIG_DETECT_HUNG_TASK is not set -# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -CONFIG_ATOMIC64_SELFTEST=y - -CONFIG_MEMORY_FAILURE=y -CONFIG_HWPOISON_INJECT=m CONFIG_CLEANCACHE=y - -CONFIG_BLK_DEV_DRBD=m +CONFIG_FRONTSWAP=y # CONFIG_MDIO_GPIO is not set # CONFIG_KEYBOARD_GPIO is not set # CONFIG_KEYBOARD_GPIO_POLLED is not set # CONFIG_MOUSE_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set # CONFIG_I2C_GPIO is not set # CONFIG_DEBUG_GPIO is not set # CONFIG_W1_MASTER_GPIO is not set @@ -4620,45 +4682,25 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_SCH is not set # CONFIG_GPIO_LANGWELL is not set # CONFIG_GPIO_RDC321X is not set -# CONFIG_GPIO_BASIC_MMIO is not set # CONFIG_GPIO_VX855 is not set # CONFIG_GPIO_PCH is not set # CONFIG_GPIO_ML_IOH is not set - -CONFIG_KSYM_TRACER=y -CONFIG_PROFILE_KSYM_TRACER=y -CONFIG_KPROBE_EVENT=y - -# CONFIG_RAMOOPS is not set - -CONFIG_IR_CORE=m -CONFIG_IR_ENE=m -CONFIG_IR_STREAMZAP=m -CONFIG_IR_WINBOND_CIR=m +# CONFIG_GPIO_AMD8111 is not set # CONFIG_GPIO_SX150X is not set -# CONFIG_MFD_STMPE is not set -# CONFIG_MFD_MAX8998 is not set -# CONFIG_MFD_TPS6586X is not set -# CONFIG_MFD_TC3589X is not set - -CONFIG_SPARSE_RCU_POINTER=y - -# CONFIG_PM_OPP is not set - -CONFIG_BKL=y +# FIXME: Why? CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_TEST_KSTRTOX=y # CONFIG_XZ_DEC_TEST is not set -CONFIG_NFC_DEVICES=y -CONFIG_PN544_NFC=m -CONFIG_NFC_PN533=m +# CONFIG_POWER_AVS is not set CONFIG_TARGET_CORE=m +CONFIG_ISCSI_TARGET=m CONFIG_LOOPBACK_TARGET=m -# CONFIG_LOOPBACK_TARGET_CDB_DEBUG is not set +CONFIG_SBP_TARGET=m CONFIG_TCM_IBLOCK=m CONFIG_TCM_FILEIO=m CONFIG_TCM_PSCSI=m @@ -4667,6 +4709,9 @@ CONFIG_TCM_FC=m CONFIG_HWSPINLOCK=m CONFIG_PSTORE=y +CONFIG_PSTORE_RAM=m +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_FTRACE is not set # CONFIG_AVERAGE is not set @@ -4674,13 +4719,17 @@ CONFIG_PSTORE=y CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -CONFIG_TEST_KSTRTOX=m - CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y # CONFIG_BCMA_DEBUG is not set # CONFIG_GOOGLE_FIRMWARE is not set -CONFIG_INTEL_MID_PTI=m - CONFIG_IOMMU_SUPPORT=y + +# CONFIG_HSI is not set + +# CONFIG_PM_DEVFREQ is not set + diff --git a/config-ia64-generic b/config-ia64-generic deleted file mode 100644 index f469b9621..000000000 --- a/config-ia64-generic +++ /dev/null @@ -1,202 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Processor type and features -# -CONFIG_IA64=y -CONFIG_64BIT=y -# CONFIG_XEN is not set -CONFIG_MMU=y -CONFIG_EFI=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -CONFIG_IA64_GENERIC=y -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_ZX1 is not set -# CONFIG_IA64_SGI_SN2 is not set -CONFIG_IA64_ESI=y -CONFIG_IA64_HP_AML_NFW=y -CONFIG_MSPEC=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_NUMA=y -# CONFIG_VIRTUAL_MEM_MAP is not set -CONFIG_SPARSEMEM_MANUAL=y -CONFIG_SPARSEMEM=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTREMOVE=y -CONFIG_IA64_MCA_RECOVERY=m -CONFIG_IA64_CYCLONE=y -CONFIG_MMTIMER=y -CONFIG_IOSAPIC=y -CONFIG_FORCE_MAX_ZONEORDER=18 -CONFIG_NR_CPUS=1024 -# CONFIG_IA32_SUPPORT is not set -# CONFIG_COMPAT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -CONFIG_EFI_VARS=y -CONFIG_SERIAL_8250_RUNTIME_UARTS=16 -CONFIG_EFI_PCDP=y -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_BLK_DEV_SGIIOC4=y - -# -# Character devices -# -CONFIG_TCG_INFINEON=m - -# -# Watchdog Cards -# -# CONFIG_HW_RANDOM is not set -# CONFIG_GEN_RTC is not set -CONFIG_EFI_RTC=y -CONFIG_RTC_DRV_EFI=y - - -# -# AGP -# -CONFIG_AGP_I460=y -CONFIG_AGP_HP_ZX1=y -CONFIG_AGP_SGI_TIOCA=y - -# -# HP Simulator drivers -# -# CONFIG_HP_SIMETH is not set -# CONFIG_HP_SIMSERIAL is not set -# CONFIG_HP_SIMSCSI is not set - -# -# Kernel hacking -# -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# SGI -# -CONFIG_SGI_SNSC=y -CONFIG_SGI_TIOCX=y -CONFIG_SGI_MBCS=m -CONFIG_SGI_IOC3=m -CONFIG_SGI_IOC4=y -CONFIG_SGI_XP=m -CONFIG_SGI_GRU=m -# CONFIG_SGI_GRU_DEBUG is not set -CONFIG_SERIAL_SGI_L1_CONSOLE=y -CONFIG_SERIAL_SGI_IOC3=m -CONFIG_SERIAL_SGI_IOC4=m - - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_BUSLOGIC is not set - -# -CONFIG_ACPI=y -CONFIG_ACPI_AC=y -# CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y -# CONFIG_ACPI_BATTERY is not set -CONFIG_ACPI_BLACKLIST_YEAR=0 -CONFIG_ACPI_BUTTON=y -# CONFIG_ACPI_DOCK is not set -CONFIG_ACPI_FAN=y -CONFIG_ACPI_HOTPLUG_MEMORY=y -CONFIG_ACPI_NUMA=y -CONFIG_ACPI_POWER=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_PROCFS=y -CONFIG_ACPI_SLEEP=y -CONFIG_ACPI_THERMAL=y -# CONFIG_ACPI_TOSHIBA is not set -CONFIG_ACPI_VIDEO=m -# CONFIG_ACPI_PROC_EVENT is not set -CONFIG_ACPI_HED=m -CONFIG_ACPI_EC_DEBUGFS=m -CONFIG_ACPI_IPMI=m -CONFIG_ACPI_CUSTOM_METHOD=m -CONFIG_SENSORS_ACPI_POWER=m - -CONFIG_PM=y -CONFIG_HOTPLUG_PCI=y -# CONFIG_HPET is not set -# CONFIG_HOTPLUG_PCI_CPCI is not set -CONFIG_HOTPLUG_PCI_SHPC=m -CONFIG_HOTPLUG_PCI_SGI=m -CONFIG_PNPACPI=y - -CONFIG_SCHED_SMT=y - -CONFIG_ARCH_DISCONTIGMEM_ENABLE=y - -CONFIG_IA64_ACPI_CPUFREQ=m - -# CONFIG_PERMIT_BSP_REMOVE is not set -# CONFIG_FORCE_CPEI_RETARGET is not set - -CONFIG_NODES_SHIFT=10 - - -CONFIG_HW_RANDOM_INTEL=m - -CONFIG_CRASH_DUMP=y -CONFIG_PROC_VMCORE=y - -# drivers/media/video/usbvision/usbvision-i2c.c:64:39: error: macro "outb" passed 4 arguments, but takes just 2 -# CONFIG_VIDEO_USBVISION is not set - -# CONFIG_IA64_MC_ERR_INJECT is not set - -CONFIG_DMIID=y -CONFIG_DMI_SYSFS=y - -CONFIG_SENSORS_I5K_AMB=m - -CONFIG_SPARSEMEM_VMEMMAP=y - -CONFIG_FRAME_WARN=2048 - -CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_KVM_INTEL=m - -CONFIG_HP_ILO=m - -CONFIG_PARAVIRT_GUEST=y -CONFIG_PARAVIRT=y - -CONFIG_DMAR_DEFAULT_ON=y - -CONFIG_RCU_FANOUT=64 - -CONFIG_ACPI_POWER_METER=m -CONFIG_I2C_SCMI=m - -# CONFIG_HP_ACCEL is not set diff --git a/config-nodebug b/config-nodebug index a3fbf944d..516a45e4a 100644 --- a/config-nodebug +++ b/config-nodebug @@ -2,101 +2,109 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_DEBUG=y CONFIG_SND_PCM_XRUN_DEBUG=y -CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_ATOMIC_SLEEP is not set -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set CONFIG_DEBUG_VM=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_PROVE_RCU=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_PROVE_RCU is not set # CONFIG_PROVE_RCU_REPEATEDLY is not set -CONFIG_DEBUG_PER_CPU_MAPS=y +# CONFIG_DEBUG_PER_CPU_MAPS is not set CONFIG_CPUMASK_OFFSTACK=y -CONFIG_CPU_NOTIFIER_ERROR_INJECT=m +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set -CONFIG_FAULT_INJECTION=y -CONFIG_FAILSLAB=y -CONFIG_FAIL_PAGE_ALLOC=y -CONFIG_FAIL_MAKE_REQUEST=y -CONFIG_FAULT_INJECTION_DEBUG_FS=y -CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y -CONFIG_FAIL_IO_TIMEOUT=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FAILSLAB is not set +# CONFIG_FAIL_PAGE_ALLOC is not set +# CONFIG_FAIL_MAKE_REQUEST is not set +# CONFIG_FAULT_INJECTION_DEBUG_FS is not set +# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set +# CONFIG_FAIL_IO_TIMEOUT is not set +# CONFIG_FAIL_MMC_REQUEST is not set -CONFIG_SLUB_DEBUG_ON=y +# CONFIG_SLUB_DEBUG_ON is not set -CONFIG_LOCK_STAT=y +# CONFIG_LOCK_STAT is not set -CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_ACPI_DEBUG=y +# CONFIG_ACPI_DEBUG is not set # CONFIG_ACPI_DEBUG_FUNC_TRACE is not set -CONFIG_DEBUG_SG=y +# CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_PAGEALLOC is not set -CONFIG_DEBUG_WRITECOUNT=y -CONFIG_DEBUG_OBJECTS=y +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_OBJECTS is not set # CONFIG_DEBUG_OBJECTS_SELFTEST is not set -CONFIG_DEBUG_OBJECTS_FREE=y -CONFIG_DEBUG_OBJECTS_TIMERS=y -CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +# CONFIG_DEBUG_OBJECTS_FREE is not set +# CONFIG_DEBUG_OBJECTS_TIMERS is not set +# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 -CONFIG_X86_PTDUMP=y +# CONFIG_X86_PTDUMP is not set -CONFIG_CAN_DEBUG_DEVICES=y +# CONFIG_CAN_DEBUG_DEVICES is not set -CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_SYSCTL_SYSCALL_CHECK is not set -CONFIG_DEBUG_NOTIFIERS=y +# CONFIG_DEBUG_NOTIFIERS is not set -CONFIG_DMA_API_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set -CONFIG_MMIOTRACE=y +# CONFIG_MMIOTRACE is not set -CONFIG_DEBUG_CREDENTIALS=y +# CONFIG_DEBUG_CREDENTIALS is not set # off in both production debug and nodebug builds, # on in rawhide nodebug builds -CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -CONFIG_EXT4_DEBUG=y +# CONFIG_EXT4_DEBUG is not set -CONFIG_DEBUG_PERF_USE_VMALLOC=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set -CONFIG_JBD2_DEBUG=y +# CONFIG_JBD2_DEBUG is not set -CONFIG_DEBUG_CFQ_IOSCHED=y +# CONFIG_DEBUG_BLK_CGROUP is not set -CONFIG_DRBD_FAULT_INJECTION=y +# CONFIG_DRBD_FAULT_INJECTION is not set -CONFIG_ATH_DEBUG=y -CONFIG_CARL9170_DEBUGFS=y -CONFIG_IWLWIFI_DEVICE_TRACING=y +# CONFIG_ATH_DEBUG is not set +# CONFIG_CARL9170_DEBUGFS is not set +# CONFIG_IWLWIFI_DEVICE_TRACING is not set -CONFIG_DEBUG_OBJECTS_WORK=y -# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_OBJECTS_WORK is not set -CONFIG_DMADEVICES_DEBUG=y -CONFIG_DMADEVICES_VDEBUG=y +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMADEVICES_VDEBUG is not set CONFIG_PM_ADVANCED_DEBUG=y -CONFIG_CEPH_LIB_PRETTYDEBUG=y -CONFIG_QUOTA_DEBUG=y +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_QUOTA_DEBUG is not set CONFIG_PCI_DEFAULT_USE_CRS=y CONFIG_KGDB_KDB=y CONFIG_KDB_KEYBOARD=y -CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_TEST_LIST_SORT=y +# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set +# CONFIG_TEST_LIST_SORT is not set -CONFIG_DEBUG_SET_MODULE_RONX=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set + +# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set + +# CONFIG_MAC80211_MESSAGE_TRACING is not set + +# CONFIG_EDAC_DEBUG is not set diff --git a/config-powerpc-generic b/config-powerpc-generic index 97baa8a83..063d8f764 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -38,15 +38,16 @@ CONFIG_AGP_UNINORTH=y CONFIG_FB_OF=y # CONFIG_FB_CONTROL is not set CONFIG_FB_IBM_GXT4500=y -CONFIG_FB_RADEON=y CONFIG_FB_MATROX=y -CONFIG_FB_NVIDIA=m # CONFIG_FB_VGA16 is not set CONFIG_FB_ATY128_BACKLIGHT=y CONFIG_FB_ATY_BACKLIGHT=y -CONFIG_FB_RADEON_BACKLIGHT=y CONFIG_FB_RIVA_BACKLIGHT=y -CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set +# CONFIG_FB_MB862XX_LIME is not set +# CONFIG_FB_MB862XX_I2C is not set + CONFIG_SND_POWERMAC=m CONFIG_SND_POWERMAC_AUTO_DRC=y @@ -159,7 +160,7 @@ CONFIG_IDE_TASK_IOCTL=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC=m CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_BLK_DEV_HD is not set @@ -175,14 +176,14 @@ CONFIG_PMAC_APM_EMU=m CONFIG_HW_RANDOM_PASEMI=m CONFIG_EDAC=y -# CONFIG_EDAC_DEBUG is not set CONFIG_EDAC_MM_EDAC=m CONFIG_EDAC_PASEMI=m CONFIG_EDAC_AMD8131=m CONFIG_EDAC_AMD8111=m +CONFIG_EDAC_LEGACY_SYSFS=y -CONFIG_AXON_RAM=m -CONFIG_OPROFILE_CELL=y +# CONFIG_AXON_RAM is not set +# CONFIG_OPROFILE_CELL is not set CONFIG_SUSPEND_FREEZER=y # CONFIG_IDEPCI_PCIBUS_ORDER is not set @@ -192,7 +193,7 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y # CONFIG_MPC5121_ADS is not set # CONFIG_MPC5121_GENERIC is not set -CONFIG_MTD_OF_PARTS=m +CONFIG_MTD_OF_PARTS=y # CONFIG_MTD_NAND_FSL_ELBC is not set CONFIG_THERMAL=y @@ -203,9 +204,9 @@ CONFIG_DMADEVICES=y CONFIG_SND_PPC=y -CONFIG_PPC_82xx=y -CONFIG_PPC_83xx=y -CONFIG_PPC_86xx=y +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_86xx is not set CONFIG_EXTRA_TARGETS="" # CONFIG_CODE_PATCHING_SELFTEST is not set # CONFIG_FTR_FIXUP_SELFTEST is not set @@ -219,27 +220,28 @@ CONFIG_EXTRA_TARGETS="" # CONFIG_SERIAL_QE is not set # CONFIG_I2C_CPM is not set +CONFIG_NET_VENDOR_IBM=y -CONFIG_SERIO_XILINX_XPS_PS2=m +# CONFIG_SERIO_XILINX_XPS_PS2 is not set # CONFIG_PPC_SMLPAR is not set -CONFIG_MGCOGE=y -CONFIG_GEF_SBC610=y -CONFIG_GEF_PPC9A=y -CONFIG_GEF_SBC310=y +# CONFIG_MGCOGE is not set +# CONFIG_GEF_SBC610 is not set +# CONFIG_GEF_PPC9A is not set +# CONFIG_GEF_SBC310 is not set -CONFIG_QUICC_ENGINE=y -CONFIG_QE_GPIO=y -CONFIG_MPC8xxx_GPIO=y +# CONFIG_QUICC_ENGINE is not set +# CONFIG_QE_GPIO is not set +# CONFIG_MPC8xxx_GPIO is not set CONFIG_IDE_GD=y CONFIG_IDE_GD_ATA=y CONFIG_IDE_GD_ATAPI=y -CONFIG_MCU_MPC8349EMITX=m +# CONFIG_MCU_MPC8349EMITX is not set -CONFIG_GPIO_XILINX=y +# CONFIG_GPIO_XILINX is not set CONFIG_PMIC_DA903X=y CONFIG_BACKLIGHT_DA903X=m @@ -260,11 +262,11 @@ CONFIG_TOUCHSCREEN_DA9034=m CONFIG_SIMPLE_GPIO=y -CONFIG_FSL_PQ_MDIO=m +# CONFIG_FSL_PQ_MDIO is not set -CONFIG_PS3_VRAM=m +# CONFIG_PS3_VRAM is not set CONFIG_MDIO_GPIO=m -CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL=m +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set # CONFIG_DEBUG_GPIO is not set CONFIG_GPIO_PCA953X=m CONFIG_GPIO_PCF857X=m @@ -272,8 +274,6 @@ CONFIG_GPIO_PCF857X=m # CONFIG_USB_FHCI_HCD is not set # CONFIG_FHCI_DEBUG is not set -# CONFIG_DRM_RADEON_KMS is not set - # CONFIG_AMIGAONE is not set CONFIG_PPC_OF_BOOT_TRAMPOLINE=y @@ -294,38 +294,41 @@ CONFIG_SWIOTLB=y CONFIG_PPC_DISABLE_WERROR=y -CONFIG_XILINX_LL_TEMAC=m -CONFIG_XILINX_EMACLITE=m +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_EMACLITE is not set CONFIG_GPIO_WM831X=m # CONFIG_GPIO_LANGWELL is not set # CONFIG_GPIO_UCB1400 is not set -CONFIG_EDAC_MPC85XX=m +# CONFIG_EDAC_MPC85XX is not set CONFIG_NR_IRQS=512 CONFIG_SPARSE_IRQ=y -CONFIG_PPC_MPC5200_LPBFIFO=m -CONFIG_CAN_MSCAN=m -CONFIG_CAN_MPC5XXX=m +# CONFIG_PPC_MPC5200_LPBFIFO is not set +# CONFIG_CAN_MSCAN is not set +# CONFIG_CAN_MPC5XXX is not set CONFIG_PATA_MACIO=m CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m # CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_88PM8607 is not set # CONFIG_MFD_MAX8997 is not set # CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set # CONFIG_MFD_WL1273_CORE is not set # CONFIG_XPS_USB_HCD_XILINX is not set # CONFIG_MMC_SDHCI_OF_ESDHC is not set # CONFIG_MMC_SDHCI_OF_HLWD is not set # CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_AAT2870_CORE is not set # CONFIG_GPIO_SCH is not set # CONFIG_PPC_MPC512x is not set +# CONFIG_RTC_DRV_MPC5121 is not set -CONFIG_MPC512X_DMA=m +# CONFIG_MPC512X_DMA is not set CONFIG_KVM_GUEST=y @@ -336,13 +339,33 @@ CONFIG_I2C_MPC=m CONFIG_RFKILL_GPIO=m -CONFIG_CRYPTO_DEV_FSL_CAAM=m -CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC=y -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD=255 -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD=2048 -CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=m +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set # CONFIG_GPIO_GENERIC_PLATFORM is not set # CONFIG_GPIO_MCP23S08 is not set +# CONFIG_CAN_FLEXCAN is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_IBM_EMAC is not set +# CONFIG_NET_VENDOR_PASEMI is not set +# CONFIG_NET_VENDOR_TOSHIBA is not set + +# Disable btrfs until it is shown to work with 64k pages (rhbz 747079) +# CONFIG_BTRFS_FS is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_CPU_IDLE is not set +CONFIG_STRICT_DEVMEM=y + +CONFIG_RCU_FANOUT_LEAF=16 + +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_MPIC_MSGR is not set +# CONFIG_FA_DUMP is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set + +# CONFIG_FAIL_IOMMU is not set diff --git a/config-powerpc32-generic b/config-powerpc32-generic index 31c399e65..e856b9ff0 100644 --- a/config-powerpc32-generic +++ b/config-powerpc32-generic @@ -7,17 +7,17 @@ CONFIG_PPC32=y CONFIG_CPU_FREQ_PMAC=y CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y -CONFIG_PPC_MPC52xx=y +# CONFIG_PPC_MPC52xx is not set CONFIG_PPC_PREP=y # CONFIG_PPC_MPC5200_SIMPLE is not set -CONFIG_SATA_FSL=m +# CONFIG_SATA_FSL is not set # CONFIG_SATA_NV is not set # busted in .28git1 # ERROR: "cacheable_memzero" [drivers/net/gianfar_driver.ko] undefined! # CONFIG_GIANFAR is not set -CONFIG_USB_EHCI_FSL=y +# CONFIG_USB_EHCI_FSL is not set CONFIG_PMAC_APM_EMU=y CONFIG_PMAC_BACKLIGHT=y @@ -41,6 +41,7 @@ CONFIG_ADB_PMU_LED=y CONFIG_ADB_PMU_LED_IDE=y CONFIG_PMAC_MEDIABAY=y +CONFIG_NET_VENDOR_APPLE=y CONFIG_BMAC=m CONFIG_MACE=m # CONFIG_MACE_AAUI_PORT is not set @@ -72,24 +73,20 @@ CONFIG_BRIQ_PANEL=m # CONFIG_ATA_PIIX is not set # CONFIG_PATA_AMD is not set # CONFIG_PATA_ATIIXP is not set -CONFIG_PATA_MPC52xx=m +# CONFIG_PATA_MPC52xx is not set # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set # CONFIG_PATA_OPTI is not set # CONFIG_PATA_SERVERWORKS is not set -CONFIG_SERIAL_MPC52xx=y -CONFIG_SERIAL_MPC52xx_CONSOLE=y -CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200 +# CONFIG_SERIAL_MPC52xx is not set # CONFIG_MPC5200_WDT is not set CONFIG_8xxx_WDT=m CONFIG_GEF_WDT=m -CONFIG_PPC_MPC5200_BUGFIX=y -CONFIG_FEC_MPC52xx=m +# CONFIG_PPC_MPC5200_BUGFIX is not set +# CONFIG_NET_VENDOR_FREESCALE is not set #CHECK: This may later become a tristate. -CONFIG_FEC_MPC52xx_MDIO=y -CONFIG_PPC_MPC5200_GPIO=y CONFIG_MDIO_GPIO=m CONFIG_SERIAL_OF_PLATFORM=y @@ -144,26 +141,28 @@ CONFIG_VIRTUALIZATION=y CONFIG_SND_ISA=y CONFIG_CRYPTO_DEV_TALITOS=m -CONFIG_FSL_EMB_PERFMON=y -CONFIG_MPC8272_ADS=y -CONFIG_PQ2FADS=y -CONFIG_EP8248E=y -CONFIG_MPC830x_RDB=y -CONFIG_MPC831x_RDB=y -CONFIG_MPC832x_MDS=y -CONFIG_MPC832x_RDB=y -CONFIG_MPC834x_MDS=y -CONFIG_MPC834x_ITX=y -CONFIG_MPC836x_MDS=y -CONFIG_MPC836x_RDK=y -CONFIG_MPC837x_MDS=y -CONFIG_MPC837x_RDB=y -CONFIG_SBC834x=y -CONFIG_ASP834x=y -CONFIG_KMETER1=y -CONFIG_MPC8641_HPCN=y -CONFIG_SBC8641D=y -CONFIG_MPC8610_HPCD=y +# CONFIG_FSL_EMB_PERFMON is not set +# CONFIG_MPC8272_ADS is not set +# CONFIG_PQ2FADS is not set +# CONFIG_EP8248E is not set +# CONFIG_MPC830x_RDB is not set +# CONFIG_MPC831x_RDB is not set +# CONFIG_MPC832x_MDS is not set +# CONFIG_MPC832x_RDB is not set +# CONFIG_MPC834x_MDS is not set +# CONFIG_MPC834x_ITX is not set +# CONFIG_MPC836x_MDS is not set +# CONFIG_MPC836x_RDK is not set +# CONFIG_MPC837x_MDS is not set +# CONFIG_MPC837x_RDB is not set +# CONFIG_SBC834x is not set +# CONFIG_ASP834x is not set +# CONFIG_KMETER1 is not set +# CONFIG_MPC8641_HPCN is not set +# CONFIG_SBC8641D is not set +# CONFIG_MPC8610_HPCD is not set +# CONFIG_FSL_LBC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set # CONFIG_USB_MUSB_HDRC is not set @@ -172,8 +171,6 @@ CONFIG_MPC8610_HPCD=y # drivers/mtd/maps/sbc8240.c:172: warning: passing argument 1 of 'simple_map_init' from incompatible pointer type # drivers/mtd/maps/sbc8240.c:177: error: 'struct mtd_info' has no member named 'module' -CONFIG_MTD_NAND_FSL_UPM=m - CONFIG_RCU_FANOUT=32 CONFIG_PERF_COUNTERS=y @@ -185,3 +182,4 @@ CONFIG_KVM_BOOK3S_32=m # CONFIG_SCSI_QLA_ISCSI is not set CONFIG_BATTERY_PMU=m + diff --git a/config-powerpc64 b/config-powerpc64 index 8e7d75d42..708e3115b 100644 --- a/config-powerpc64 +++ b/config-powerpc64 @@ -1,49 +1,33 @@ +CONFIG_WINDFARM_PM72=y CONFIG_WINDFARM_PM81=y CONFIG_WINDFARM_PM91=y CONFIG_WINDFARM_PM121=y +CONFIG_WINDFARM_RM31=y CONFIG_PPC_PMAC64=y CONFIG_PPC_MAPLE=y -CONFIG_PPC_CELL=y -CONFIG_PPC_IBM_CELL_BLADE=y +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_IBM_CELL_BLADE is not set CONFIG_PPC_ISERIES=y CONFIG_PPC_PSERIES=y CONFIG_PPC_PMAC=y -CONFIG_PPC_PASEMI=y +CONFIG_PPC_POWERNV=y +CONFIG_PPC_POWERNV_RTAS=y +# CONFIG_PPC_PASEMI is not set # CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE is not set -CONFIG_PPC_PS3=y -CONFIG_PPC_CELLEB=y -CONFIG_PPC_CELL_QPACE=y -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_ADVANCED=y -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_VUART=y -CONFIG_PS3_PS3AV=y -CONFIG_PS3_STORAGE=m -CONFIG_PS3_DISK=m -CONFIG_PS3_ROM=m -CONFIG_PS3_FLASH=m -CONFIG_PS3_LPM=y -CONFIG_SND_PS3=m -CONFIG_SND_PS3_DEFAULT_START_DELAY=1000 -CONFIG_GELIC_NET=m -CONFIG_GELIC_WIRELESS=y -CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE=y -CONFIG_CBE_THERM=m -CONFIG_CBE_CPUFREQ=m -CONFIG_CBE_CPUFREQ_PMI=m -CONFIG_CBE_CPUFREQ_PMI_ENABLE=y +# CONFIG_PPC_PS3 is not set +# CONFIG_PPC_CELLEB is not set +# CONFIG_PPC_CELL_QPACE is not set CONFIG_PMAC_RACKMETER=m CONFIG_IBMEBUS=y -CONFIG_SPU_FS=m CONFIG_RTAS_FLASH=y +# CONFIG_UDBG_RTAS_CONSOLE is not set CONFIG_PPC_SPLPAR=y CONFIG_SCANLOG=y CONFIG_LPARCFG=y CONFIG_SERIAL_ICOM=m CONFIG_HVCS=m CONFIG_HVC_CONSOLE=y +# CONFIG_HVC_OLD_HVSI is not set CONFIG_HOTPLUG_PCI=y CONFIG_THERM_PM72=y CONFIG_IBMVETH=m @@ -56,13 +40,13 @@ CONFIG_ADB_PMU_LED=y CONFIG_ADB_PMU_LED_IDE=y CONFIG_PMAC_SMU=y CONFIG_CPU_FREQ_PMAC64=y +CONFIG_CPU_FREQ_MAPLE=y CONFIG_SCSI_IPR=m CONFIG_SCSI_IPR_TRACE=y CONFIG_SCSI_IPR_DUMP=y -CONFIG_SPIDER_NET=m CONFIG_HVC_RTAS=y CONFIG_HVC_ISERIES=y -CONFIG_CBE_RAS=y +CONFIG_HVC_OPAL=y # iSeries device drivers # @@ -74,19 +58,13 @@ CONFIG_VIOTAPE=m CONFIG_PASEMI_MAC=m CONFIG_SERIAL_OF_PLATFORM=m -CONFIG_PPC_PASEMI_IOMMU=y CONFIG_SERIAL_TXX9=y CONFIG_SERIAL_TXX9_NR_UARTS=6 CONFIG_SERIAL_TXX9_CONSOLE=y CONFIG_HVC_BEAT=y -CONFIG_FB_PS3=y -CONFIG_FB_PS3_DEFAULT_SIZE_M=18 - CONFIG_PPC_PMI=m -CONFIG_PS3_SYS_MANAGER=y -# CONFIG_BLK_DEV_CELLEB is not set CONFIG_PATA_SCC=m @@ -94,7 +72,7 @@ CONFIG_APM_EMULATION=m CONFIG_PPC64=y CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_NR_CPUS=128 +CONFIG_NR_CPUS=1024 # CONFIG_FB_PLATINUM is not set # CONFIG_FB_VALKYRIE is not set # CONFIG_FB_CT65550 is not set @@ -107,9 +85,16 @@ CONFIG_NR_CPUS=128 CONFIG_RTAS_PROC=y CONFIG_IOMMU_VMERGE=y CONFIG_NUMA=y -# CONFIG_PPC_64K_PAGES is not set +CONFIG_PPC_64K_PAGES=y +CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set + +CONFIG_MEMORY_HOTREMOVE=y + # CONFIG_MV643XX_ETH is not set CONFIG_IRQSTACKS=y CONFIG_DEBUG_STACKOVERFLOW=y @@ -118,7 +103,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_EHEA=m CONFIG_INFINIBAND_EHCA=m -CONFIG_HCALL_STATS=y +# CONFIG_HCALL_STATS is not set CONFIG_XMON_DISASSEMBLY=y @@ -130,24 +115,14 @@ CONFIG_SECCOMP=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y # CONFIG_BLK_DEV_PLATFORM is not set -CONFIG_IBM_NEW_EMAC=m -CONFIG_IBM_NEW_EMAC_RXB=128 -CONFIG_IBM_NEW_EMAC_TXB=64 -CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32 -CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256 -CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0 -# CONFIG_IBM_NEW_EMAC_DEBUG is not set # CONFIG_VIRQ_DEBUG is not set -CONFIG_ELECTRA_CF=m -CONFIG_MTD_NAND_PASEMI=m -CONFIG_EDAC_CELL=m CONFIG_EDAC_CPC925=m CONFIG_FRAME_WARN=2048 CONFIG_PHYP_DUMP=y -CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_FORCE_MAX_ZONEORDER=9 CONFIG_VIRTUALIZATION=y CONFIG_VSX=y @@ -156,14 +131,6 @@ CONFIG_SCSI_IBMVFC=m # CONFIG_SCSI_IBMVFC_TRACE is not set CONFIG_IBM_BSR=m -CONFIG_SERIO_XILINX_XPS_PS2=m - -CONFIG_PPC_IBM_CELL_RESETBUTTON=y -CONFIG_PPC_IBM_CELL_POWERBUTTON=m -CONFIG_CBE_CPUFREQ_SPU_GOVERNOR=m - -CONFIG_RTC_DRV_PS3=y - CONFIG_CRASH_DUMP=y CONFIG_RELOCATABLE=y @@ -174,6 +141,8 @@ CONFIG_PERF_EVENTS=y CONFIG_EVENT_PROFILE=y CONFIG_KVM_BOOK3S_64=m +#-- Enable _HV once publicly available POWER7 hardware can use it +# CONFIG_KVM_BOOK3S_64_HV is not set # CONFIG_KVM_EXIT_TIMING is not set #-- bz#607175 @@ -181,7 +150,9 @@ CONFIG_KVM_BOOK3S_64=m CONFIG_PPC_SMLPAR=y CONFIG_CMM=y #-- DLPAR memory remove -# CONFIG_SPARSEMEM_VMEMMAP is not set +CONFIG_SPARSEMEM_VMEMMAP=y + +# CONFIG_COMPACTION is not set CONFIG_PSERIES_ENERGY=m @@ -189,4 +160,11 @@ CONFIG_PPC_ICSWX=y CONFIG_IO_EVENT_IRQ=y CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_PSERIES=m +CONFIG_CRYPTO_DEV_NX=m + CONFIG_BPF_JIT=y + +# CONFIG_PPC_ICSWX_PID is not set +# CONFIG_PPC_ICSWX_USE_SIGILL is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set diff --git a/config-s390x b/config-s390x index da9db13c1..e68ad4750 100644 --- a/config-s390x +++ b/config-s390x @@ -197,6 +197,7 @@ CONFIG_QETH_L3=m CONFIG_CRYPTO_SHA512_S390=m CONFIG_VIRTUALIZATION=y CONFIG_KVM=m +# CONFIG_KVM_S390_UCONTROL is not set CONFIG_S390_GUEST=y @@ -210,6 +211,7 @@ CONFIG_CHSC_SCH=m CONFIG_HVC_IUCV=y CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=8 CONFIG_SECCOMP=y @@ -236,5 +238,6 @@ CONFIG_STRICT_DEVMEM=y # CONFIG_WARN_DYNAMIC_STACK is not set -CONFIG_JUMP_LABEL=y CONFIG_CRYPTO_GHASH_S390=m +CONFIG_NET_CORE=y +CONFIG_ETHERNET=y diff --git a/config-sparc64-generic b/config-sparc64-generic index 8cc28f74a..a27e0b44b 100644 --- a/config-sparc64-generic +++ b/config-sparc64-generic @@ -43,6 +43,7 @@ CONFIG_I2C_ALI1535=m # CONFIG_VGASTATE is not set # CONFIG_FB_DDC is not set # CONFIG_FB_BW2 is not set +# CONFIG_FB_GRVGA is not set CONFIG_FB_CG3=y CONFIG_FB_CG6=y # CONFIG_FB_RIVA is not set @@ -172,6 +173,7 @@ CONFIG_LEDS_SUNFIRE=m CONFIG_TADPOLE_TS102_UCTRL=m CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 CONFIG_LIRC_ENE0100=m # CONFIG_BATTERY_DS2782 is not set @@ -191,8 +193,10 @@ CONFIG_FB_XVR1000=y CONFIG_CRYPTO_DEV_NIAGARA2=y -CONFIG_JUMP_LABEL=y - # CONFIG_MTD_OF_PARTS is not set # CONFIG_MTD_PHYSMAP_OF is not set # CONFIG_MMC_SDHCI_OF is not set +# CONFIG_OF_SELFTEST is not set + +CONFIG_BPF_JIT=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set diff --git a/config-x86-32-generic b/config-x86-32-generic new file mode 100644 index 000000000..5b9805a97 --- /dev/null +++ b/config-x86-32-generic @@ -0,0 +1,219 @@ +# CONFIG_64BIT is not set + +CONFIG_X86_32_NON_STANDARD=y + +# CONFIG_X86_ELAN is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +CONFIG_X86_BIGSMP=y +# CONFIG_X86_VISWS is not set +# CONFIG_X86_RDC321X is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set + +CONFIG_NR_CPUS=32 +CONFIG_X86_GENERIC=y +# CONFIG_X86_PPRO_FENCE is not set + +CONFIG_TOSHIBA=m + +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y + +# CONFIG_NUMA is not set + +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y + +# CONFIG_MATH_EMULATION is not set + +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=y +CONFIG_FB_GEODE_GX=y +# CONFIG_FB_GEODE_GX1 is not set + +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +CONFIG_PCI_GOANY=y + +CONFIG_IBM_ASM=m + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set + +CONFIG_ACPI_BLACKLIST_YEAR=1999 + + +# CONFIG_X86_POWERNOW_K6 is not set +CONFIG_X86_POWERNOW_K7=y +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=y +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +# e_powersaver is dangerous +# CONFIG_X86_E_POWERSAVER is not set + +CONFIG_X86_HT=y +CONFIG_X86_TRAMPOLINE=y + + +# CONFIG_4KSTACKS is not set + +CONFIG_PCI_DIRECT=y + +# SHPC has half-arsed PCI probing, which makes it load on too many systems +# CONFIG_HOTPLUG_PCI_SHPC is not set + +CONFIG_BLK_DEV_AMD74XX=y + +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m + +CONFIG_SCx200_ACB=m + +# CONFIG_X86_REBOOTFIXUPS is not set + +CONFIG_PC8736x_GPIO=m +# CONFIG_NSC_GPIO is not set +CONFIG_CS5535_GPIO=m +CONFIG_GPIO_SCH=m + +CONFIG_SND_ISA=y +CONFIG_SND_ES18XX=m + +CONFIG_HW_RANDOM_GEODE=m + +# CONFIG_SGI_IOC4 is not set + +CONFIG_TC1100_WMI=m + +CONFIG_IB700_WDT=m + +CONFIG_PHYSICAL_ALIGN=0x400000 +CONFIG_PHYSICAL_START=0x400000 + +# CONFIG_KEXEC_JUMP is not set + +CONFIG_CRYPTO_AES_586=y +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_CRYPTO_TWOFISH_586=m + +CONFIG_VIDEO_CAFE_CCIC=m + +CONFIG_XEN_MAX_DOMAIN_MEMORY=8 + +CONFIG_MTD_NAND_CAFE=m + +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set + + +CONFIG_OLPC=y +CONFIG_OLPC_OPENFIRMWARE=y +CONFIG_BATTERY_OLPC=y +CONFIG_MOUSE_PS2_OLPC=y +CONFIG_OLPC_XO1_PM=y +CONFIG_OLPC_XO15_SCI=y +CONFIG_OLPC_XO1_RTC=y +CONFIG_OLPC_XO1_SCI=y +# CONFIG_ALIX is not set +# staging +# CONFIG_FB_OLPC_DCON is not set + +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# CONFIG_SPARSE_IRQ is not set + +CONFIG_RCU_FANOUT=32 + +# CONFIG_X86_ANCIENT_MCE is not set + +# CONFIG_X86_MRST is not set + +CONFIG_I2C_PXA=m +# CONFIG_GPIO_LANGWELL is not set + +# CONFIG_INTEL_TXT is not set + +CONFIG_GEODE_WDT=m +CONFIG_CS5535_MFGPT=m +CONFIG_CS5535_CLOCK_EVENT_SRC=m + +CONFIG_LEDS_INTEL_SS4200=m + +CONFIG_OLPC_XO1=m +CONFIG_XO1_RFKILL=m + +CONFIG_X86_32_IRIS=m + + +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_PHYSMAP_OF=m +CONFIG_PROC_DEVICETREE=y +CONFIG_SERIAL_OF_PLATFORM=m +CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m +# CONFIG_MMC_SDHCI_OF is not set + +# CONFIG_X86_INTEL_MID is not set + +CONFIG_MFD_CS5535=m + +# I2O enabled only for 32-bit x86, disabled for PAE kernel +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_I2O_CONFIG=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m + +# CONFIG_EDAC_SBRIDGE is not set + +# CONFIG_X86_WANT_INTEL_MID is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_GEOS is not set +# CONFIG_NET5501 is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_GPIO_SODAVILLE is not set +# CONFIG_BACKLIGHT_OT200 is not set + +# CONFIG_STA2X11 is not set + diff --git a/config-x86-generic b/config-x86-generic index f41bb9095..77f95933a 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -1,216 +1,123 @@ CONFIG_UID16=y -# CONFIG_64BIT is not set -# CONFIG_KERNEL_LZMA is not set -# -# Processor type and features -# -# -# Enable summit and co via the generic arch -# CONFIG_X86_EXTENDED_PLATFORM=y -CONFIG_X86_32_NON_STANDARD=y -# CONFIG_X86_ELAN is not set -# CONFIG_X86_NUMAQ is not set -# CONFIG_X86_SUMMIT is not set -CONFIG_X86_BIGSMP=y -# CONFIG_X86_VISWS is not set -# CONFIG_X86_RDC321X is not set -# CONFIG_X86_ES7000 is not set -# CONFIG_M386 is not set -# CONFIG_M486 is not set -# CONFIG_M586 is not set -# CONFIG_M586TSC is not set -# CONFIG_M586MMX is not set -CONFIG_M686=y -# CONFIG_MPENTIUMII is not set -# CONFIG_MPENTIUMIII is not set -# CONFIG_MPENTIUMM is not set -# CONFIG_MPENTIUM4 is not set -# CONFIG_MK6 is not set -# CONFIG_MK7 is not set -# CONFIG_MK8 is not set -# CONFIG_MCRUSOE is not set -# CONFIG_MWINCHIPC6 is not set -# CONFIG_MWINCHIP3D is not set -# CONFIG_MCYRIXIII is not set -# CONFIG_MVIAC3_2 is not set CONFIG_SMP=y -CONFIG_NR_CPUS=64 + CONFIG_X86_GENERIC=y -# CONFIG_X86_PPRO_FENCE is not set + CONFIG_HPET=y CONFIG_HPET_TIMER=y # CONFIG_HPET_MMAP is not set -CONFIG_X86_MCE=y -CONFIG_TOSHIBA=m + CONFIG_I8K=m -CONFIG_SONYPI=m CONFIG_SONYPI_COMPAT=y CONFIG_MICROCODE=m +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_AMD=y + CONFIG_X86_MSR=y CONFIG_X86_CPUID=y CONFIG_EDD=m # CONFIG_EDD_OFF is not set -# CONFIG_NUMA is not set -# CONFIG_NOHIGHMEM is not set -CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set -CONFIG_HIGHMEM=y -CONFIG_HIGHPTE=y - -# CONFIG_MATH_EMULATION is not set CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 CONFIG_X86_PAT=y CONFIG_X86_PM_TIMER=y CONFIG_EFI=y +CONFIG_EFI_STUB=y CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y CONFIG_FB_EFI=y + +# FIXME: 32bit only? # CONFIG_FB_N411 is not set -CONFIG_DMAR=y +CONFIG_INTEL_IOMMU=y CONFIG_DMAR_BROKEN_GFX_WA=y -CONFIG_DMAR_FLOPPY_WA=y -CONFIG_DMAR_DEFAULT_ON=y - -CONFIG_FB_GEODE=y -CONFIG_FB_GEODE_LX=y -CONFIG_FB_GEODE_GX=y -# CONFIG_FB_GEODE_GX1 is not set - -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GODIRECT is not set -# CONFIG_PCI_GOMMCONFIG is not set -CONFIG_PCI_GOANY=y - -# -# x86 specific drivers -# -CONFIG_PCMCIA_FDOMAIN=m -CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set CONFIG_SCSI_ADVANSYS=m -CONFIG_CC_STACKPROTECTOR=y - CONFIG_SECCOMP=y CONFIG_CAPI_EICON=y -# I2O enabled only for 32-bit x86, disabled for PAE kernel -CONFIG_I2O=m -CONFIG_I2O_BLOCK=m -CONFIG_I2O_SCSI=m -CONFIG_I2O_PROC=m -CONFIG_I2O_CONFIG=y -CONFIG_I2O_EXT_ADAPTEC=y -CONFIG_I2O_CONFIG_OLD_IOCTL=y -CONFIG_I2O_BUS=m - -# -# APM (Advanced Power Management) BIOS Support -# -CONFIG_APM=y -# CONFIG_APM_IGNORE_USER_SUSPEND is not set -# CONFIG_APM_DO_ENABLE is not set -CONFIG_APM_CPU_IDLE=y -# CONFIG_APM_DISPLAY_BLANK is not set -# CONFIG_APM_ALLOW_INTS is not set - # # Kernel debugging # CONFIG_X86_MPPARSE=y +# CONFIG_X86_VERBOSE_BOOTUP is not set +# CONFIG_MMIOTRACE_TEST is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_DEBUG_RODATA=y +CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_ACPI=y CONFIG_ACPI_AC=y # CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y CONFIG_ACPI_BATTERY=y -CONFIG_ACPI_BLACKLIST_YEAR=1999 CONFIG_ACPI_BUTTON=y CONFIG_ACPI_CONTAINER=m CONFIG_ACPI_DOCK=y CONFIG_ACPI_FAN=y CONFIG_ACPI_NUMA=y CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_POWER=y CONFIG_ACPI_PROCFS=y CONFIG_ACPI_SBS=m CONFIG_ACPI_SLEEP=y CONFIG_ACPI_THERMAL=y -CONFIG_TOPSTAR_LAPTOP=m CONFIG_ACPI_TOSHIBA=m CONFIG_ACPI_VIDEO=m +# FIXME: Next two are deprecated. Remove them when they disappear upstream +# CONFIG_ACPI_PROCFS_POWER is not set # CONFIG_ACPI_PROC_EVENT is not set CONFIG_PNPACPI=y -CONFIG_ACPI_POWER_METER=m CONFIG_ACPI_PROCESSOR_AGGREGATOR=m CONFIG_ACPI_HED=m CONFIG_ACPI_APEI=y CONFIG_ACPI_APEI_PCIEAER=y -CONFIG_ACPI_APEI_GHES=m +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_MEMORY_FAILURE=y # CONFIG_ACPI_APEI_EINJ is not set CONFIG_ACPI_IPMI=m CONFIG_ACPI_CUSTOM_METHOD=m +CONFIG_ACPI_BGRT=m CONFIG_X86_ACPI_CPUFREQ=y CONFIG_X86_PCC_CPUFREQ=y -# CONFIG_X86_POWERNOW_K6 is not set -CONFIG_X86_POWERNOW_K7=y CONFIG_X86_POWERNOW_K8=y -# CONFIG_X86_GX_SUSPMOD is not set -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -CONFIG_X86_SPEEDSTEP_ICH=y -CONFIG_X86_SPEEDSTEP_SMI=y -CONFIG_X86_SPEEDSTEP_LIB=y -# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set CONFIG_X86_P4_CLOCKMOD=y -CONFIG_X86_LONGRUN=y -# CONFIG_X86_LONGHAUL is not set -# CONFIG_X86_CPUFREQ_NFORCE2 is not set -# e_powersaver is dangerous -# CONFIG_X86_E_POWERSAVER is not set - -CONFIG_X86_HT=y -CONFIG_X86_TRAMPOLINE=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set # # various x86 specific drivers # CONFIG_NVRAM=y -CONFIG_IBM_ASM=m -CONFIG_CRYPTO_TWOFISH_586=m CONFIG_CRYPTO_DEV_PADLOCK=m CONFIG_CRYPTO_DEV_PADLOCK_AES=m CONFIG_CRYPTO_DEV_PADLOCK_SHA=m CONFIG_GENERIC_ISA_DMA=y -CONFIG_SCHED_SMT=y + CONFIG_SUSPEND=y CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="" -CONFIG_DEBUG_RODATA=y -CONFIG_DEBUG_STACKOVERFLOW=y -# CONFIG_4KSTACKS is not set -CONFIG_DEBUG_NMI_TIMEOUT=5 - -CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y CONFIG_PCI_BIOS=y +CONFIG_PCI_IOAPIC=y CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_COMPAQ=m # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set CONFIG_HOTPLUG_PCI_IBM=m # CONFIG_HOTPLUG_PCI_CPCI is not set -# SHPC has half-arsed PCI probing, which makes it load on too many systems -# CONFIG_HOTPLUG_PCI_SHPC is not set + CONFIG_PM=y CONFIG_IPW2100=m @@ -223,9 +130,6 @@ CONFIG_IPW2200_QOS=y CONFIG_BLK_DEV_AMD74XX=y -CONFIG_I2C_ALI1535=m -CONFIG_I2C_ALI15X3=m -CONFIG_I2C_ALI1563=m CONFIG_I2C_AMD756=m CONFIG_I2C_AMD756_S4882=m CONFIG_I2C_AMD8111=m @@ -234,45 +138,35 @@ CONFIG_I2C_ISCH=m CONFIG_I2C_NFORCE2=m CONFIG_I2C_NFORCE2_S4985=m CONFIG_I2C_PIIX4=m -CONFIG_I2C_SIS5595=m -CONFIG_I2C_SIS630=m CONFIG_I2C_SIS96X=m - CONFIG_I2C_VIA=m CONFIG_I2C_VIAPRO=m -CONFIG_SCx200_ACB=m - -# CONFIG_X86_REBOOTFIXUPS is not set - CONFIG_DELL_RBU=m CONFIG_DCDBAS=m -CONFIG_GPIO_SCH=m -CONFIG_PC8736x_GPIO=m -# CONFIG_NSC_GPIO is not set -CONFIG_CS5535_GPIO=m - CONFIG_EDAC=y -# CONFIG_EDAC_DEBUG is not set CONFIG_EDAC_MM_EDAC=m CONFIG_EDAC_AMD76X=m +CONFIG_EDAC_AMD8111=m +CONFIG_EDAC_AMD8131=m CONFIG_EDAC_E7XXX=m CONFIG_EDAC_E752X=m CONFIG_EDAC_I82860=m CONFIG_EDAC_I82875P=m CONFIG_EDAC_I82975X=m CONFIG_EDAC_I3000=m +CONFIG_EDAC_I3200=m CONFIG_EDAC_I5000=m CONFIG_EDAC_I5100=m CONFIG_EDAC_I5400=m -CONFIG_EDAC_R82600=m -CONFIG_EDAC_AMD8131=m -CONFIG_EDAC_AMD8111=m -CONFIG_EDAC_I7CORE=m -CONFIG_EDAC_I3000=m CONFIG_EDAC_I7300=m +CONFIG_EDAC_I7CORE=m +CONFIG_EDAC_R82600=m CONFIG_EDAC_X38=m +CONFIG_EDAC_MCE_INJ=m +CONFIG_EDAC_DECODE_MCE=m +CONFIG_EDAC_LEGACY_SYSFS=y CONFIG_SCHED_MC=y @@ -283,83 +177,80 @@ CONFIG_TCG_INFINEON=m CONFIG_HW_RANDOM_INTEL=m CONFIG_HW_RANDOM_AMD=m -CONFIG_HW_RANDOM_GEODE=m CONFIG_HW_RANDOM_VIA=m - # CONFIG_COMPAT_VDSO is not set -# CONFIG_SGI_IOC4 is not set - CONFIG_X86_PLATFORM_DEVICES=y + CONFIG_ASUS_LAPTOP=m CONFIG_COMPAL_LAPTOP=m +CONFIG_DELL_LAPTOP=m CONFIG_EEEPC_LAPTOP=m -CONFIG_EEEPC_WMI=m CONFIG_FUJITSU_LAPTOP=m # CONFIG_FUJITSU_LAPTOP_DEBUG is not set CONFIG_IDEAPAD_LAPTOP=m CONFIG_MSI_LAPTOP=m +CONFIG_PANASONIC_LAPTOP=m +CONFIG_SAMSUNG_LAPTOP=m CONFIG_SONY_LAPTOP=m -CONFIG_DELL_LAPTOP=m +CONFIG_TOPSTAR_LAPTOP=m +CONFIG_FUJITSU_TABLET=m +CONFIG_AMILO_RFKILL=m + + CONFIG_ACPI_WMI=m CONFIG_ACER_WMI=m CONFIG_ACERHDF=m -CONFIG_TC1100_WMI=m +CONFIG_ASUS_WMI=m +CONFIG_ASUS_NB_WMI=m CONFIG_HP_WMI=m # CONFIG_INTEL_SCU_IPC is not set CONFIG_DELL_WMI=m CONFIG_DELL_WMI_AIO=m -CONFIG_ASUS_WMI=m -CONFIG_ASUS_NB_WMI=m -CONFIG_XO15_EBOOK=m +CONFIG_EEEPC_WMI=m CONFIG_INTEL_OAKTRAIL=m +CONFIG_SAMSUNG_Q10=m +CONFIG_XO15_EBOOK=m # CONFIG_TOUCHSCREEN_INTEL_MID is not set # CONFIG_SMSC37B787_WDT is not set CONFIG_W83697HF_WDT=m -CONFIG_IB700_WDT=m +CONFIG_VIA_WDT=m +CONFIG_IE6XX_WDT=m -CONFIG_RELOCATABLE=y -CONFIG_PHYSICAL_ALIGN=0x400000 -CONFIG_PHYSICAL_START=0x400000 CONFIG_CRASH_DUMP=y -# CONFIG_KEXEC_JUMP is not set CONFIG_PROC_VMCORE=y CONFIG_CRASH=m -CONFIG_CRYPTO_DEV_GEODE=m - -CONFIG_VIDEO_CAFE_CCIC=m - CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_KVM_INTEL=m CONFIG_KVM_AMD=m CONFIG_LGUEST=m +CONFIG_LGUEST_GUEST=y CONFIG_PARAVIRT_GUEST=y CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y # CONFIG_PARAVIRT_DEBUG is not set -# PARAVIRT_SPINLOCKS has a 5% perf hit +# PARAVIRT_SPINLOCKS has a 5% perf hit on native hw (see kconfig) # CONFIG_PARAVIRT_SPINLOCKS is not set + CONFIG_KVM_CLOCK=y CONFIG_KVM_GUEST=y CONFIG_KVM_MMU_AUDIT=y # default $x would be nice... -CONFIG_LGUEST_GUEST=y -CONFIG_VMI=y CONFIG_XEN=y # CONFIG_XEN_DEBUG is not set -CONFIG_XEN_MAX_DOMAIN_MEMORY=8 CONFIG_XEN_BALLOON=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_SAVE_RESTORE=y CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XEN_KBDDEV_FRONTEND=y CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m CONFIG_XEN_NETDEV_BACKEND=m @@ -371,15 +262,15 @@ CONFIG_XEN_COMPAT_XENFS=y CONFIG_XEN_BACKEND=y CONFIG_XEN_BLKDEV_BACKEND=m CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_PLATFORM_PCI=m +CONFIG_XEN_PLATFORM_PCI=y CONFIG_XEN_GNTDEV=m CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m CONFIG_XEN_SELFBALLOONING=y CONFIG_XEN_PCIDEV_BACKEND=m +CONFIG_XEN_ACPI_PROCESSOR=m CONFIG_MTD_ESB2ROM=m CONFIG_MTD_CK804XROM=m -CONFIG_MTD_NAND_CAFE=m CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -411,152 +302,118 @@ CONFIG_SENSORS_FAM15H_POWER=m CONFIG_SENSORS_ACPI_POWER=m # CONFIG_CPA_DEBUG is not set -# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set CONFIG_HP_WATCHDOG=m CONFIG_NV_TCO=m CONFIG_SP5100_TCO=m -CONFIG_OLPC=y -CONFIG_OLPC_OPENFIRMWARE=y -CONFIG_BATTERY_OLPC=y -CONFIG_MOUSE_PS2_OLPC=y - -# staging -# CONFIG_FB_OLPC_DCON is not set - CONFIG_STRICT_DEVMEM=y # CONFIG_NO_BOOTMEM is not set # CONFIG_MEMTEST is not set +# CONFIG_DEBUG_TLBFLUSH is not set # CONFIG_MAXSMP is not set -CONFIG_MTRR_SANITIZER=y -CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 -CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 -CONFIG_SYSPROF_TRACER=y -# CONFIG_X86_VERBOSE_BOOTUP is not set -# CONFIG_MMIOTRACE_TEST is not set - -# CONFIG_DEBUG_PER_CPU_MAPS is not set CONFIG_HP_ILO=m CONFIG_BACKLIGHT_APPLE=m -CONFIG_OPROFILE_IBS=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_AMD=y -# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set -CONFIG_X86_RESERVE_LOW_64K=y +CONFIG_X86_CHECK_BIOS_CORRUPTION=y # CONFIG_CMDLINE_BOOL is not set -CONFIG_PANASONIC_LAPTOP=m - -CONFIG_X86_PTRACE_BTS=y CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y -CONFIG_POWER_TRACER=y -CONFIG_HW_BRANCH_TRACER=y - -# CONFIG_SPARSE_IRQ is not set - -CONFIG_RCU_FANOUT=32 # CONFIG_IOMMU_STRESS is not set CONFIG_PERF_COUNTERS=y CONFIG_PERF_EVENTS=y -CONFIG_EVENT_PROFILE=y +CONFIG_X86_MCE=y CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_AMD=y -# CONFIG_X86_ANCIENT_MCE is not set # CONFIG_X86_MCE_INJECT is not set -# CONFIG_X86_MRST is not set CONFIG_SFI=y -CONFIG_INPUT_WINBOND_CIR=m CONFIG_I2C_SCMI=m -CONFIG_I2C_PXA=m CONFIG_SBC_FITPC2_WATCHDOG=m -CONFIG_EDAC_I3200=m -CONFIG_EDAC_DECODE_MCE=m - -# CONFIG_GPIO_LANGWELL is not set - -# CONFIG_INTEL_TXT is not set - -CONFIG_CS5535_MFGPT=m -CONFIG_GEODE_WDT=m -CONFIG_CS5535_CLOCK_EVENT_SRC=m - -CONFIG_LEDS_INTEL_SS4200=m CONFIG_X86_DECODER_SELFTEST=y CONFIG_ACPI_CMPC=m CONFIG_MSI_WMI=m CONFIG_TOSHIBA_BT_RFKILL=m -# CONFIG_SAMSUNG_LAPTOP is not set CONFIG_VGA_SWITCHEROO=y CONFIG_LPC_SCH=m +CONFIG_GPIO_ICH=m + CONFIG_PCI_CNB20LE_QUIRK=y CONFIG_ACPI_EC_DEBUGFS=m # CONFIG_ACPI_APEI_ERST_DEBUG is not set +# CONFIG_ACPI_QUICKSTART is not set + CONFIG_INTEL_IDLE=y + # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set -CONFIG_SENSORS_PKGTEMP=m CONFIG_F71808E_WDT=m CONFIG_HPWDT_NMI_DECODING=y # CONFIG_MFD_TPS6586X is not set # CONFIG_INTEL_MID_DMAC is not set CONFIG_PCH_DMA=m -# CONFIG_ACPI_QUICKSTART is not set -CONFIG_IDEAPAD_ACPI=m CONFIG_INTEL_IPS=m # CONFIG_IBM_RTL is not set -CONFIG_OLPC_XO1=m -CONFIG_XO1_RFKILL=m CONFIG_VIDEO_VIA_CAMERA=m - -CONFIG_EDAC_MCE_INJ=m +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_X86_RESERVE_LOW=64 +# CONFIG_IRQ_DOMAIN_DEBUG is not set + CONFIG_PCH_GBE=m CONFIG_PCH_PHUB=m -CONFIG_JUMP_LABEL=y - -CONFIG_X86_32_IRIS=m - CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_CRYPTO_AES_NI_INTEL=y -CONFIG_CRYPTO_AES_586=y - -CONFIG_MTD_OF_PARTS=m -CONFIG_MTD_PHYSMAP_OF=m -CONFIG_PROC_DEVICETREE=y -CONFIG_SERIAL_OF_PLATFORM=m -CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m -# CONFIG_MMC_SDHCI_OF is not set +CONFIG_CRYPTO_SERPENT_SSE2_586=m CONFIG_HP_ACCEL=m # CONFIG_RAPIDIO is not set -# CONFIG_X86_INTEL_MID is not set - # CONFIG_GPIO_GENERIC_PLATFORM is not set # CONFIG_GPIO_MCP23S08 is not set + +CONFIG_SCHED_SMT=y +CONFIG_CC_STACKPROTECTOR=y +CONFIG_RELOCATABLE=y + +CONFIG_HYPERV=m +CONFIG_HYPERV_UTILS=m +CONFIG_HID_HYPERV_MOUSE=m +CONFIG_HYPERV_NET=m +CONFIG_HYPERV_STORAGE=m + +# Depends on PCI +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m + +CONFIG_DRM_GMA500=m +# CONFIG_DRM_GMA600 is not set +# CONFIG_DRM_GMA3600 is not set + +CONFIG_RCU_FANOUT_LEAF=16 + +# Maybe enable in debug kernels? +# CONFIG_DEBUG_NMI_SELFTEST is not set + +CONFIG_APPLE_GMUX=m diff --git a/config-x86_64-generic b/config-x86_64-generic index 340d7472d..8d300df57 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -1,229 +1,70 @@ CONFIG_64BIT=y -CONFIG_UID16=y -# CONFIG_KERNEL_LZMA is not set +# CONFIG_X86_X32 is not set # CONFIG_MK8 is not set # CONFIG_MPSC is not set CONFIG_GENERIC_CPU=y -CONFIG_X86_EXTENDED_PLATFORM=y + # CONFIG_X86_VSMP is not set # CONFIG_X86_UV is not set -CONFIG_X86_MSR=y -CONFIG_X86_CPUID=y -CONFIG_MTRR=y CONFIG_NUMA=y CONFIG_K8_NUMA=y CONFIG_AMD_NUMA=y CONFIG_X86_64_ACPI_NUMA=y # CONFIG_NUMA_EMU is not set -CONFIG_NR_CPUS=512 -CONFIG_X86_POWERNOW_K8=m -CONFIG_X86_P4_CLOCKMOD=m +# CONFIG_X86_NUMACHIP is not set + + +CONFIG_NR_CPUS=256 +CONFIG_PHYSICAL_START=0x1000000 + CONFIG_IA32_EMULATION=y # CONFIG_IA32_AOUT is not set + +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_STATS=y +CONFIG_AMD_IOMMU_V2=m # CONFIG_IOMMU_DEBUG is not set -CONFIG_DEBUG_RODATA=y -CONFIG_MICROCODE=m CONFIG_SWIOTLB=y -CONFIG_CALGARY_IOMMU=y -CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y -CONFIG_X86_PM_TIMER=y -CONFIG_EDD=m -# CONFIG_EDD_OFF is not set -CONFIG_PCI_BIOS=y -CONFIG_PCI_MMCONFIG=y -CONFIG_DMAR=y -CONFIG_DMAR_BROKEN_GFX_WA=y -CONFIG_DMAR_FLOPPY_WA=y -CONFIG_DMAR_DEFAULT_ON=y +# CONFIG_CALGARY_IOMMU is not set CONFIG_KEXEC_JUMP=y -CONFIG_EFI=y -CONFIG_EFI_VARS=y -CONFIG_EFI_PCDP=y -CONFIG_FB_EFI=y - -CONFIG_SCSI_ADVANSYS=m - -CONFIG_SECCOMP=y - -CONFIG_CAPI_EICON=y - -CONFIG_GENERIC_ISA_DMA=y -CONFIG_SCHED_SMT=y -CONFIG_SUSPEND=y -CONFIG_HIBERNATION=y -CONFIG_PM_STD_PARTITION="" - -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -CONFIG_X86_PCC_CPUFREQ=y -CONFIG_X86_ACPI_CPUFREQ=y - -CONFIG_ACPI=y -CONFIG_ACPI_AC=y -# CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y -CONFIG_ACPI_BATTERY=y CONFIG_ACPI_BLACKLIST_YEAR=0 -CONFIG_ACPI_BUTTON=y -CONFIG_ACPI_CONTAINER=m -CONFIG_ACPI_DOCK=y -CONFIG_ACPI_FAN=y CONFIG_ACPI_HOTPLUG_MEMORY=m -CONFIG_ACPI_NUMA=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_PROCFS=y -CONFIG_ACPI_SBS=m -CONFIG_ACPI_SLEEP=y -CONFIG_ACPI_THERMAL=y -CONFIG_ACPI_TOSHIBA=m -CONFIG_ACPI_POWER=y -CONFIG_ACPI_VIDEO=m -# CONFIG_ACPI_PROC_EVENT is not set -CONFIG_ACPI_POWER_METER=m -CONFIG_ACPI_PROCESSOR_AGGREGATOR=m -CONFIG_ACPI_HED=m -CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_PCIEAER=y -CONFIG_ACPI_APEI_GHES=m -# CONFIG_ACPI_APEI_EINJ is not set -CONFIG_ACPI_IPMI=m -CONFIG_ACPI_CUSTOM_METHOD=m - -CONFIG_X86_PLATFORM_DEVICES=y -CONFIG_ASUS_LAPTOP=m -CONFIG_COMPAL_LAPTOP=m -CONFIG_FUJITSU_LAPTOP=m -# CONFIG_FUJITSU_LAPTOP_DEBUG is not set -CONFIG_MSI_LAPTOP=m -CONFIG_SONY_LAPTOP=m -CONFIG_SONYPI_COMPAT=y -CONFIG_EEEPC_LAPTOP=m -CONFIG_EEEPC_WMI=m -CONFIG_DELL_LAPTOP=m -CONFIG_ACPI_WMI=m -CONFIG_ACER_WMI=m -CONFIG_ACERHDF=m -CONFIG_HP_WMI=m -CONFIG_DELL_WMI=m -CONFIG_DELL_WMI_AIO=m -CONFIG_ASUS_WMI=m -CONFIG_ASUS_NB_WMI=m -# CONFIG_XO15_EBOOK is not set -CONFIG_INTEL_OAKTRAIL=m # CONFIG_INTEL_SCU_IPC is not set -# CONFIG_TOUCHSCREEN_INTEL_MID is not set - -CONFIG_THINKPAD_ACPI=m -# CONFIG_THINKPAD_ACPI_DEBUG is not set -# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set -CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y -CONFIG_THINKPAD_ACPI_VIDEO=y -CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y -# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set - -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_COMPAQ=m -# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set -CONFIG_HOTPLUG_PCI_IBM=m -# CONFIG_HOTPLUG_PCI_CPCI is not set # SHPC has half-arsed PCI probing, which makes it load on too many systems CONFIG_HOTPLUG_PCI_SHPC=m -CONFIG_HPET=y -# CONFIG_HPET_MMAP is not set -CONFIG_PM=y - -CONFIG_IPW2100=m -CONFIG_IPW2100_MONITOR=y -CONFIG_IPW2200=m -CONFIG_IPW2200_MONITOR=y -CONFIG_IPW2200_RADIOTAP=y -CONFIG_IPW2200_PROMISCUOUS=y -CONFIG_IPW2200_QOS=y - CONFIG_PNP=y -CONFIG_PNPACPI=y +# Really ? not 32bit only ? CONFIG_BLK_DEV_AMD74XX=y -CONFIG_CRYPTO_DEV_PADLOCK=m -CONFIG_CRYPTO_DEV_PADLOCK_AES=m -CONFIG_CRYPTO_DEV_PADLOCK_SHA=m CONFIG_CRYPTO_AES_X86_64=y -CONFIG_CRYPTO_AES_NI_INTEL=y - +CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m CONFIG_CRYPTO_TWOFISH_X86_64=m CONFIG_CRYPTO_SALSA20_X86_64=m - -CONFIG_X86_MCE=y -CONFIG_X86_MCE_INTEL=y -CONFIG_X86_MCE_AMD=y +CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m +CONFIG_CRYPTO_SHA1_SSSE3=m +CONFIG_CRYPTO_BLOWFISH_X86_64=m +CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m +CONFIG_CRYPTO_CAMELLIA_X86_64=m +CONFIG_CRYPTO_SERPENT_AVX_X86_64=m +CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m # CONFIG_I2C_ALI1535 is not set # CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set -CONFIG_I2C_AMD756=m -CONFIG_I2C_AMD756_S4882=m -CONFIG_I2C_AMD8111=m -CONFIG_I2C_I801=m -CONFIG_I2C_ISCH=m -CONFIG_I2C_NFORCE2_S4985=m -CONFIG_I2C_PIIX4=m # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set -CONFIG_I2C_SIS96X=m -CONFIG_I2C_VIA=m -CONFIG_I2C_VIAPRO=m - -CONFIG_DELL_RBU=m -CONFIG_DCDBAS=m - -CONFIG_NVRAM=y - -CONFIG_EDAC=y -# CONFIG_EDAC_DEBUG is not set -CONFIG_EDAC_MM_EDAC=m -CONFIG_EDAC_AMD76X=m -CONFIG_EDAC_E7XXX=m -CONFIG_EDAC_E752X=m -CONFIG_EDAC_I5000=m -CONFIG_EDAC_I5100=m -CONFIG_EDAC_I5400=m -CONFIG_EDAC_I82875P=m -CONFIG_EDAC_I82860=m -CONFIG_EDAC_I82975X=m -CONFIG_EDAC_R82600=m -CONFIG_EDAC_AMD8131=m -CONFIG_EDAC_AMD8111=m CONFIG_EDAC_AMD64=m # CONFIG_EDAC_AMD64_ERROR_INJECTION is not set -CONFIG_EDAC_DECODE_MCE=m -CONFIG_EDAC_I7CORE=m -CONFIG_EDAC_I3000=m -CONFIG_EDAC_I7300=m -CONFIG_EDAC_X38=m +CONFIG_EDAC_SBRIDGE=m -CONFIG_SCHED_MC=y - -CONFIG_TCG_INFINEON=m - -CONFIG_HW_RANDOM_INTEL=m -CONFIG_HW_RANDOM_AMD=m -CONFIG_HW_RANDOM_VIA=m - -# CONFIG_HW_RANDOM_GEODE is not set - - -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_DEBUG_NMI_TIMEOUT=5 - -CONFIG_GPIO_SCH=m # CONFIG_PC8736x_GPIO is not set # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -232,8 +73,8 @@ CONFIG_SPARSEMEM=y CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTREMOVE=y +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_MEMORY_HOTREMOVE is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set @@ -242,229 +83,47 @@ CONFIG_MEMORY_HOTREMOVE=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_CS5535 is not set -CONFIG_CC_STACKPROTECTOR=y - CONFIG_SGI_IOC4=m CONFIG_SGI_XP=m CONFIG_SGI_GRU=m # CONFIG_SGI_GRU_DEBUG is not set -# CONFIG_SMSC37B787_WDT is not set -CONFIG_W83697HF_WDT=m - # CONFIG_VIDEO_CAFE_CCIC is not set -CONFIG_MTD_ESB2ROM=m -CONFIG_MTD_CK804XROM=m - -CONFIG_RELOCATABLE=y -CONFIG_MACINTOSH_DRIVERS=y - -CONFIG_CRASH_DUMP=y -CONFIG_PHYSICAL_START=0x1000000 -CONFIG_PROC_VMCORE=y -CONFIG_CRASH=m - -CONFIG_DMIID=y -CONFIG_DMI_SYSFS=y - -CONFIG_ISCSI_IBFT_FIND=y -CONFIG_ISCSI_IBFT=m - - -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_CPU_IDLE=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -CONFIG_CPU_IDLE_GOV_MENU=y - -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_KVM_INTEL=m -CONFIG_KVM_AMD=m - -CONFIG_PARAVIRT_GUEST=y -CONFIG_PARAVIRT=y -# CONFIG_PARAVIRT_DEBUG is not set -# PARAVIRT_SPINLOCKS has a 5% perf hit -# CONFIG_PARAVIRT_SPINLOCKS is not set -CONFIG_KVM_CLOCK=y -CONFIG_KVM_GUEST=y -CONFIG_KVM_MMU_AUDIT=y - -CONFIG_XEN=y -# CONFIG_XEN_DEBUG is not set -CONFIG_XEN_MAX_DOMAIN_MEMORY=32 -CONFIG_XEN_BALLOON=y -CONFIG_XEN_SCRUB_PAGES=y -CONFIG_XEN_SAVE_RESTORE=y -CONFIG_HVC_XEN=y -CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XEN_KBDDEV_FRONTEND=y -CONFIG_XEN_BLKDEV_FRONTEND=m -CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_NETDEV_BACKEND=m -CONFIG_XEN_WDT=m -CONFIG_XEN_GRANT_DEV_ALLOC=m -CONFIG_XEN_PCIDEV_FRONTEND=m -CONFIG_XENFS=m -CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_MAX_DOMAIN_MEMORY=128 +# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set CONFIG_XEN_DEV_EVTCHN=m CONFIG_XEN_SYS_HYPERVISOR=y -CONFIG_XEN_BACKEND=y -CONFIG_XEN_BLKDEV_BACKEND=m -CONFIG_XEN_GNTDEV=m -CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_PLATFORM_PCI=m -CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m -CONFIG_XEN_SELFBALLOONING=y -CONFIG_XEN_PCIDEV_BACKEND=m +# CONFIG_XEN_MCE_LOG is not set -CONFIG_DMADEVICES=y -CONFIG_INTEL_IOATDMA=m - -CONFIG_SENSORS_I5K_AMB=m -CONFIG_SENSORS_FAM15H_POWER=m -CONFIG_SENSORS_ACPI_POWER=m - -# CONFIG_COMPAT_VDSO is not set CONFIG_PROVIDE_OHCI1394_DMA_INIT=y -# CONFIG_DEBUG_PER_CPU_MAPS is not set -# CONFIG_CPA_DEBUG is not set - -CONFIG_HP_WATCHDOG=m -CONFIG_NV_TCO=m -CONFIG_SP5100_TCO=m CONFIG_FRAME_WARN=2048 CONFIG_NODES_SHIFT=9 -CONFIG_X86_PAT=y -# FIXME: These should be 32bit only -# CONFIG_FB_N411 is not set -CONFIG_STRICT_DEVMEM=y CONFIG_DIRECT_GBPAGES=y -# CONFIG_NO_BOOTMEM is not set - -# CONFIG_MEMTEST is not set -CONFIG_AMD_IOMMU=y -CONFIG_AMD_IOMMU_STATS=y -# CONFIG_MAXSMP is not set -CONFIG_MTRR_SANITIZER=y -CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 -CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 -CONFIG_SYSPROF_TRACER=y -# CONFIG_X86_VERBOSE_BOOTUP is not set -# CONFIG_MMIOTRACE_TEST is not set - CONFIG_X86_MPPARSE=y -CONFIG_BACKLIGHT_APPLE=m - -CONFIG_OPROFILE_IBS=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_AMD=y - -# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set -CONFIG_X86_RESERVE_LOW_64K=y - -# CONFIG_CMDLINE_BOOL is not set - -CONFIG_PANASONIC_LAPTOP=m - -CONFIG_X86_PTRACE_BTS=y - CONFIG_I7300_IDLE=m -CONFIG_INTR_REMAP=y - -CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y - -CONFIG_POWER_TRACER=y -CONFIG_HW_BRANCH_TRACER=y +CONFIG_IRQ_REMAP=y CONFIG_X86_X2APIC=y CONFIG_SPARSE_IRQ=y CONFIG_RCU_FANOUT=64 -# CONFIG_IOMMU_STRESS is not set - -CONFIG_PERF_COUNTERS=y -CONFIG_PERF_EVENTS=y -CONFIG_EVENT_PROFILE=y - -# CONFIG_X86_MCE_INJECT is not set - -CONFIG_SFI=y -CONFIG_INPUT_WINBOND_CIR=m -CONFIG_I2C_SCMI=m -CONFIG_SBC_FITPC2_WATCHDOG=m -CONFIG_EDAC_I3200=m -CONFIG_TOPSTAR_LAPTOP=m CONFIG_INTEL_TXT=y + CONFIG_GPIO_LANGWELL=y CONFIG_FUNCTION_GRAPH_TRACER=y -CONFIG_ACPI_CMPC=m -CONFIG_MSI_WMI=m -CONFIG_TOSHIBA_BT_RFKILL=m -# CONFIG_SAMSUNG_LAPTOP is not set - -CONFIG_CS5535_MFGPT=m -CONFIG_GEODE_WDT=m -CONFIG_CS5535_CLOCK_EVENT_SRC=m - -CONFIG_X86_DECODER_SELFTEST=y - -CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m - -CONFIG_VGA_SWITCHEROO=y -CONFIG_LPC_SCH=m - CONFIG_I7300_IDLE=m -CONFIG_PCI_CNB20LE_QUIRK=y - -CONFIG_ACPI_EC_DEBUGFS=m -# CONFIG_ACPI_APEI_ERST_DEBUG is not set -CONFIG_INTEL_IDLE=y -# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set -CONFIG_SENSORS_PKGTEMP=m -CONFIG_F71808E_WDT=m -CONFIG_HPWDT_NMI_DECODING=y -# CONFIG_MFD_TPS6586X is not set -# CONFIG_INTEL_MID_DMAC is not set -CONFIG_PCH_DMA=m -# CONFIG_ACPI_QUICKSTART is not set -CONFIG_IDEAPAD_ACPI=m -CONFIG_INTEL_IPS=m -CONFIG_IDEAPAD_LAPTOP=m -# CONFIG_IBM_RTL is not set - -CONFIG_EDAC_MCE_INJ=m -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_X86_RESERVE_LOW=64 - -CONFIG_PCH_GBE=m -CONFIG_PCH_PHUB=m - -CONFIG_VIDEO_VIA_CAMERA=m - -CONFIG_JUMP_LABEL=y - -CONFIG_HP_ILO=m - -CONFIG_TRANSPARENT_HUGEPAGE=y - -CONFIG_HP_ACCEL=m - -# CONFIG_RAPIDIO is not set - CONFIG_BPF_JIT=y -# CONFIG_GPIO_GENERIC_PLATFORM is not set -# CONFIG_GPIO_MCP23S08 is not set +# Should be 32bit only, but lacks KConfig depends +# CONFIG_XO15_EBOOK is not set diff --git a/cpupower.config b/cpupower.config new file mode 100644 index 000000000..8629a4a3e --- /dev/null +++ b/cpupower.config @@ -0,0 +1,3 @@ +# See 'cpupower help' and cpupower(1) for more info +CPUPOWER_START_OPTS="frequency-set -g performance" +CPUPOWER_STOP_OPTS="frequency-set -g ondemand" diff --git a/cpupower.service b/cpupower.service new file mode 100644 index 000000000..5f10ab7ee --- /dev/null +++ b/cpupower.service @@ -0,0 +1,13 @@ +[Unit] +Description=Configure CPU power related settings +After=syslog.target + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/etc/sysconfig/cpupower +ExecStart=/usr/bin/cpupower $CPUPOWER_START_OPTS +ExecStop=/usr/bin/cpupower $CPUPOWER_STOP_OPTS + +[Install] +WantedBy=multi-user.target diff --git a/debug-808990.patch b/debug-808990.patch new file mode 100644 index 000000000..571bef729 --- /dev/null +++ b/debug-808990.patch @@ -0,0 +1,17 @@ +--- linux-3.3.noarch/net/ipv4/route.c~ 2012-04-02 20:24:44.162789023 -0400 ++++ linux-3.3.noarch/net/ipv4/route.c 2012-04-02 20:25:20.610784137 -0400 +@@ -2794,6 +2794,14 @@ static struct rtable *ip_route_output_sl + fl4->saddr = FIB_RES_PREFSRC(net, res); + + dev_out = FIB_RES_DEV(res); ++ ++ if (!dev_out) { ++ pr_crit("ipv4: FIB_RES_DEV() is NULL, nh_sel=%d\n", ++ res.nh_sel); ++ rth = ERR_PTR(-EINVAL); ++ goto out; ++ } ++ + fl4->flowi4_oif = dev_out->ifindex; + + diff --git a/don-t-do-blind-d_drop-in-nfs_prime_dcache.patch b/don-t-do-blind-d_drop-in-nfs_prime_dcache.patch new file mode 100644 index 000000000..d4e837ab1 --- /dev/null +++ b/don-t-do-blind-d_drop-in-nfs_prime_dcache.patch @@ -0,0 +1,27 @@ +From 696199f8ccf7fc6d17ef89c296ad3b6c78c52d9c Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Thu, 29 Nov 2012 22:00:51 -0500 +Subject: [PATCH] don't do blind d_drop() in nfs_prime_dcache() + +Signed-off-by: Al Viro +--- + fs/nfs/dir.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index ce8cb92..99489cf 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -450,7 +450,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) + nfs_refresh_inode(dentry->d_inode, entry->fattr); + goto out; + } else { +- d_drop(dentry); ++ if (d_invalidate(dentry) != 0) ++ goto out; + dput(dentry); + } + } +-- +1.8.0.1 + diff --git a/linux-2.6-v4l-dvb-experimental.patch b/drivers-media-update.patch similarity index 100% rename from linux-2.6-v4l-dvb-experimental.patch rename to drivers-media-update.patch diff --git a/drm-edid-try-harder-to-fix-up-broken-headers.patch b/drm-edid-try-harder-to-fix-up-broken-headers.patch new file mode 100644 index 000000000..26660d767 --- /dev/null +++ b/drm-edid-try-harder-to-fix-up-broken-headers.patch @@ -0,0 +1,47 @@ +From 115cb7ab7d3b87fe43b1fe9b05ec894b1fcfb5cf Mon Sep 17 00:00:00 2001 +From: Adam Jackson +Date: Wed, 7 Dec 2011 18:26:23 -0500 +Subject: [PATCH] drm/edid: Try harder to fix up broken headers + +There's no reason to force the first byte to be correct if we're already +scoring how correct the header is. + +See also: https://bugzilla.redhat.com/show_bug.cgi?id=722909 + +Signed-off-by: Adam Jackson +--- + drivers/gpu/drm/drm_edid.c | 18 ++++++++---------- + 1 files changed, 8 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 7425e5c..8b16a49 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -154,16 +154,14 @@ drm_edid_block_valid(u8 *raw_edid) + int i; + u8 csum = 0; + struct edid *edid = (struct edid *)raw_edid; +- +- if (raw_edid[0] == 0x00) { +- int score = drm_edid_header_is_valid(raw_edid); +- if (score == 8) ; +- else if (score >= 6) { +- DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); +- memcpy(raw_edid, edid_header, sizeof(edid_header)); +- } else { +- goto bad; +- } ++ int score = drm_edid_header_is_valid(raw_edid); ++ ++ if (score == 8) ; ++ else if (score >= 6) { ++ DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); ++ memcpy(raw_edid, edid_header, sizeof(edid_header)); ++ } else { ++ goto bad; + } + + for (i = 0; i < EDID_LENGTH; i++) +-- +1.7.7.3 + diff --git a/drm-i915-Use-cpu-relocations-if-the-object-is-in-the.patch b/drm-i915-Use-cpu-relocations-if-the-object-is-in-the.patch new file mode 100644 index 000000000..0e282bf04 --- /dev/null +++ b/drm-i915-Use-cpu-relocations-if-the-object-is-in-the.patch @@ -0,0 +1,33 @@ +From 504c7267a1e84b157cbd7e9c1b805e1bc0c2c846 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 23 Aug 2012 13:12:52 +0100 +Subject: [PATCH] drm/i915: Use cpu relocations if the object is in the GTT + but not mappable + +This prevents the case of unbinding the object in order to process the +relocations through the GTT and then rebinding it only to then proceed +to use cpu relocations as the object is now in the CPU write domain. By +choosing to use cpu relocations up front, we can therefore avoid the +rebind penalty. + +Signed-off-by: Chris Wilson +Signed-off-by: Daniel Vetter +--- + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c +index f7346d8..dc87563 100644 +--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c ++++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c +@@ -95,6 +95,7 @@ eb_destroy(struct eb_objects *eb) + static inline int use_cpu_reloc(struct drm_i915_gem_object *obj) + { + return (obj->base.write_domain == I915_GEM_DOMAIN_CPU || ++ !obj->map_and_fenceable || + obj->cache_level != I915_CACHE_NONE); + } + +-- +1.7.12.1 + diff --git a/drm-i915-dp-stfu.patch b/drm-i915-dp-stfu.patch new file mode 100644 index 000000000..c005a06ba --- /dev/null +++ b/drm-i915-dp-stfu.patch @@ -0,0 +1,53 @@ +diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c +index 296cfc2..516e1e2 100644 +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -350,7 +350,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) + if (!is_edp(intel_dp)) + return; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { +- WARN(1, "eDP powered off while attempting aux channel communication.\n"); ++ DRM_ERROR("eDP powered off while attempting aux channel communication.\n"); + DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); +@@ -400,7 +400,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, + } + + if (try == 3) { +- WARN(1, "dp_aux_ch not started status 0x%08x\n", ++ DRM_ERROR("dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); + return -EBUSY; + } +@@ -1024,8 +1024,8 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) + return; + DRM_DEBUG_KMS("Turn eDP VDD on\n"); + +- WARN(intel_dp->want_panel_vdd, +- "eDP VDD already requested on\n"); ++ if (intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD already requested on\n"); + + intel_dp->want_panel_vdd = true; + +@@ -1090,7 +1090,8 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) + return; + + DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); +- WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); ++ if (!intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD not forced on"); + + intel_dp->want_panel_vdd = false; + +@@ -1160,7 +1161,8 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) + + DRM_DEBUG_KMS("Turn eDP power off\n"); + +- WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); ++ if (!intel_dp->want_panel_vdd) ++ DRM_ERROR("Need VDD to turn off panel\n"); + + pp = ironlake_get_pp_control(dev_priv); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); diff --git a/drm-intel-make-lvds-work.patch b/drm-intel-make-lvds-work.patch deleted file mode 100644 index 89f4e2d48..000000000 --- a/drm-intel-make-lvds-work.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -5821,7 +5821,6 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - struct intel_load_detect_pipe *old) - { - struct drm_encoder *encoder = &intel_encoder->base; -- struct drm_device *dev = encoder->dev; - struct drm_crtc *crtc = encoder->crtc; - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; -@@ -5832,7 +5831,6 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - - if (old->load_detect_temp) { - connector->encoder = NULL; -- drm_helper_disable_unused_functions(dev); - - if (old->release_fb) - old->release_fb->funcs->destroy(old->release_fb); diff --git a/drm-nouveau-gf108.patch b/drm-nouveau-gf108.patch new file mode 100644 index 000000000..80f0d9b29 --- /dev/null +++ b/drm-nouveau-gf108.patch @@ -0,0 +1,151 @@ +diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c +index 82478e0..d8831ab 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -579,6 +579,14 @@ nouveau_card_init(struct drm_device *dev) + if (ret) + goto out_display_early; + ++ /* workaround an odd issue on nvc1 by disabling the device's ++ * nosnoop capability. hopefully won't cause issues until a ++ * better fix is found - assuming there is one... ++ */ ++ if (dev_priv->chipset == 0xc1) { ++ nv_mask(dev, 0x00088080, 0x00000800, 0x00000000); ++ } ++ + nouveau_pm_init(dev); + + ret = engine->vram.init(dev); +@@ -1102,12 +1110,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + dev_priv->noaccel = !!nouveau_noaccel; + if (nouveau_noaccel == -1) { + switch (dev_priv->chipset) { +- case 0xc1: /* known broken */ +- case 0xc8: /* never tested */ ++#if 0 ++ case 0xXX: /* known broken */ + NV_INFO(dev, "acceleration disabled by default, pass " + "noaccel=0 to force enable\n"); + dev_priv->noaccel = true; + break; ++#endif + default: + dev_priv->noaccel = false; + break; +diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c +index 4b8d0b3..3cc1c60 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_graph.c ++++ b/drivers/gpu/drm/nouveau/nvc0_graph.c +@@ -156,8 +156,8 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) + struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR); + struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + int i = 0, gpc, tp, ret; +- u32 magic; + + ret = nouveau_gpuobj_new(dev, chan, 0x2000, 256, NVOBJ_FLAG_VM, + &grch->unk408004); +@@ -206,14 +206,37 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) + nv_wo32(grch->mmio, i++ * 4, 0x0041880c); + nv_wo32(grch->mmio, i++ * 4, 0x80000018); + +- magic = 0x02180000; +- nv_wo32(grch->mmio, i++ * 4, 0x00405830); +- nv_wo32(grch->mmio, i++ * 4, magic); +- for (gpc = 0; gpc < priv->gpc_nr; gpc++) { +- for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x0324) { +- u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800); +- nv_wo32(grch->mmio, i++ * 4, reg); +- nv_wo32(grch->mmio, i++ * 4, magic); ++ if (dev_priv->chipset != 0xc1) { ++ u32 magic = 0x02180000; ++ nv_wo32(grch->mmio, i++ * 4, 0x00405830); ++ nv_wo32(grch->mmio, i++ * 4, magic); ++ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { ++ for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { ++ u32 reg = TP_UNIT(gpc, tp, 0x520); ++ nv_wo32(grch->mmio, i++ * 4, reg); ++ nv_wo32(grch->mmio, i++ * 4, magic); ++ magic += 0x0324; ++ } ++ } ++ } else { ++ u32 magic = 0x02180000; ++ nv_wo32(grch->mmio, i++ * 4, 0x00405830); ++ nv_wo32(grch->mmio, i++ * 4, magic | 0x0000218); ++ nv_wo32(grch->mmio, i++ * 4, 0x004064c4); ++ nv_wo32(grch->mmio, i++ * 4, 0x0086ffff); ++ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { ++ for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { ++ u32 reg = TP_UNIT(gpc, tp, 0x520); ++ nv_wo32(grch->mmio, i++ * 4, reg); ++ nv_wo32(grch->mmio, i++ * 4, (1 << 28) | magic); ++ magic += 0x0324; ++ } ++ for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { ++ u32 reg = TP_UNIT(gpc, tp, 0x544); ++ nv_wo32(grch->mmio, i++ * 4, reg); ++ nv_wo32(grch->mmio, i++ * 4, magic); ++ magic += 0x0324; ++ } + } + } + +diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c +index dd0e6a7..96b0b93d 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grctx.c ++++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c +@@ -1812,6 +1812,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) + /* calculate first set of magics */ + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + ++ gpc = -1; + for (tp = 0; tp < priv->tp_total; tp++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; +@@ -1861,30 +1862,26 @@ nvc0_grctx_generate(struct nouveau_channel *chan) + + if (1) { + u32 tp_mask = 0, tp_set = 0; +- u8 tpnr[GPC_MAX]; ++ u8 tpnr[GPC_MAX], a, b; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) + tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8); + +- gpc = -1; +- for (i = 0, gpc = -1; i < 32; i++) { +- int ltp = i * (priv->tp_total - 1) / 32; +- +- do { +- gpc = (gpc + 1) % priv->gpc_nr; +- } while (!tpnr[gpc]); +- tp = priv->tp_nr[gpc] - tpnr[gpc]--; ++ for (i = 0, gpc = -1, b = -1; i < 32; i++) { ++ a = (i * (priv->tp_total - 1)) / 32; ++ if (a != b) { ++ b = a; ++ do { ++ gpc = (gpc + 1) % priv->gpc_nr; ++ } while (!tpnr[gpc]); ++ tp = priv->tp_nr[gpc] - tpnr[gpc]--; + +- tp_set |= 1 << ((gpc * 8) + tp); ++ tp_set |= 1 << ((gpc * 8) + tp); ++ } + +- do { +- nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); +- tp_set ^= tp_mask; +- nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set); +- tp_set ^= tp_mask; +- } while (ltp == (++i * (priv->tp_total - 1) / 32)); +- i--; ++ nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); ++ nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set ^ tp_mask); + } + } + diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch index 607602cfc..cd9bded11 100644 --- a/drm-nouveau-updates.patch +++ b/drm-nouveau-updates.patch @@ -1 +1,8526 @@ -nil +diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile +index 0583677..35ef5b1 100644 +--- a/drivers/gpu/drm/nouveau/Makefile ++++ b/drivers/gpu/drm/nouveau/Makefile +@@ -21,16 +21,17 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ + nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ + nv84_crypt.o \ + nva3_copy.o nvc0_copy.o \ +- nv40_mpeg.o nv50_mpeg.o \ ++ nv31_mpeg.o nv50_mpeg.o \ + nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ +- nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ +- nv50_cursor.o nv50_display.o \ + nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ + nv04_crtc.o nv04_display.o nv04_cursor.o \ ++ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ ++ nv50_cursor.o nv50_display.o \ ++ nvd0_display.o \ + nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ + nv10_gpio.o nv50_gpio.o \ + nv50_calc.o \ +- nv04_pm.o nv50_pm.o nva3_pm.o \ ++ nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ + nv50_vram.o nvc0_vram.o \ + nv50_vm.o nvc0_vm.o + +diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c +index 00a55df..fa22b28 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c ++++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c +@@ -37,8 +37,10 @@ + #include "nouveau_drv.h" + #include "nouveau_drm.h" + #include "nouveau_reg.h" ++#include "nouveau_encoder.h" + +-static int nv40_get_intensity(struct backlight_device *bd) ++static int ++nv40_get_intensity(struct backlight_device *bd) + { + struct drm_device *dev = bl_get_data(bd); + int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) +@@ -47,7 +49,8 @@ static int nv40_get_intensity(struct backlight_device *bd) + return val; + } + +-static int nv40_set_intensity(struct backlight_device *bd) ++static int ++nv40_set_intensity(struct backlight_device *bd) + { + struct drm_device *dev = bl_get_data(bd); + int val = bd->props.brightness; +@@ -65,30 +68,8 @@ static const struct backlight_ops nv40_bl_ops = { + .update_status = nv40_set_intensity, + }; + +-static int nv50_get_intensity(struct backlight_device *bd) +-{ +- struct drm_device *dev = bl_get_data(bd); +- +- return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT); +-} +- +-static int nv50_set_intensity(struct backlight_device *bd) +-{ +- struct drm_device *dev = bl_get_data(bd); +- int val = bd->props.brightness; +- +- nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT, +- val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE); +- return 0; +-} +- +-static const struct backlight_ops nv50_bl_ops = { +- .options = BL_CORE_SUSPENDRESUME, +- .get_brightness = nv50_get_intensity, +- .update_status = nv50_set_intensity, +-}; +- +-static int nouveau_nv40_backlight_init(struct drm_connector *connector) ++static int ++nv40_backlight_init(struct drm_connector *connector) + { + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -113,34 +94,129 @@ static int nouveau_nv40_backlight_init(struct drm_connector *connector) + return 0; + } + +-static int nouveau_nv50_backlight_init(struct drm_connector *connector) ++static int ++nv50_get_intensity(struct backlight_device *bd) ++{ ++ struct nouveau_encoder *nv_encoder = bl_get_data(bd); ++ struct drm_device *dev = nv_encoder->base.base.dev; ++ int or = nv_encoder->or; ++ u32 div = 1025; ++ u32 val; ++ ++ val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); ++ val &= NV50_PDISP_SOR_PWM_CTL_VAL; ++ return ((val * 100) + (div / 2)) / div; ++} ++ ++static int ++nv50_set_intensity(struct backlight_device *bd) ++{ ++ struct nouveau_encoder *nv_encoder = bl_get_data(bd); ++ struct drm_device *dev = nv_encoder->base.base.dev; ++ int or = nv_encoder->or; ++ u32 div = 1025; ++ u32 val = (bd->props.brightness * div) / 100; ++ ++ nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), ++ NV50_PDISP_SOR_PWM_CTL_NEW | val); ++ return 0; ++} ++ ++static const struct backlight_ops nv50_bl_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .get_brightness = nv50_get_intensity, ++ .update_status = nv50_set_intensity, ++}; ++ ++static int ++nva3_get_intensity(struct backlight_device *bd) ++{ ++ struct nouveau_encoder *nv_encoder = bl_get_data(bd); ++ struct drm_device *dev = nv_encoder->base.base.dev; ++ int or = nv_encoder->or; ++ u32 div, val; ++ ++ div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); ++ val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); ++ val &= NVA3_PDISP_SOR_PWM_CTL_VAL; ++ if (div && div >= val) ++ return ((val * 100) + (div / 2)) / div; ++ ++ return 100; ++} ++ ++static int ++nva3_set_intensity(struct backlight_device *bd) ++{ ++ struct nouveau_encoder *nv_encoder = bl_get_data(bd); ++ struct drm_device *dev = nv_encoder->base.base.dev; ++ int or = nv_encoder->or; ++ u32 div, val; ++ ++ div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); ++ val = (bd->props.brightness * div) / 100; ++ if (div) { ++ nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), val | ++ NV50_PDISP_SOR_PWM_CTL_NEW | ++ NVA3_PDISP_SOR_PWM_CTL_UNK); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct backlight_ops nva3_bl_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .get_brightness = nva3_get_intensity, ++ .update_status = nva3_set_intensity, ++}; ++ ++static int ++nv50_backlight_init(struct drm_connector *connector) + { + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_encoder *nv_encoder; + struct backlight_properties props; + struct backlight_device *bd; ++ const struct backlight_ops *ops; ++ ++ nv_encoder = find_encoder(connector, OUTPUT_LVDS); ++ if (!nv_encoder) { ++ nv_encoder = find_encoder(connector, OUTPUT_DP); ++ if (!nv_encoder) ++ return -ENODEV; ++ } + +- if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT)) ++ if (!nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) + return 0; + ++ if (dev_priv->chipset <= 0xa0 || ++ dev_priv->chipset == 0xaa || ++ dev_priv->chipset == 0xac) ++ ops = &nv50_bl_ops; ++ else ++ ops = &nva3_bl_ops; ++ + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; +- props.max_brightness = 1025; +- bd = backlight_device_register("nv_backlight", &connector->kdev, dev, +- &nv50_bl_ops, &props); ++ props.max_brightness = 100; ++ bd = backlight_device_register("nv_backlight", &connector->kdev, ++ nv_encoder, ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); + + dev_priv->backlight = bd; +- bd->props.brightness = nv50_get_intensity(bd); ++ bd->props.brightness = bd->ops->get_brightness(bd); + backlight_update_status(bd); + return 0; + } + +-int nouveau_backlight_init(struct drm_connector *connector) ++int ++nouveau_backlight_init(struct drm_device *dev) + { +- struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct drm_connector *connector; + + #ifdef CONFIG_ACPI + if (acpi_video_backlight_support()) { +@@ -150,21 +226,28 @@ int nouveau_backlight_init(struct drm_connector *connector) + } + #endif + +- switch (dev_priv->card_type) { +- case NV_40: +- return nouveau_nv40_backlight_init(connector); +- case NV_50: +- return nouveau_nv50_backlight_init(connector); +- default: +- break; ++ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { ++ if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && ++ connector->connector_type != DRM_MODE_CONNECTOR_eDP) ++ continue; ++ ++ switch (dev_priv->card_type) { ++ case NV_40: ++ return nv40_backlight_init(connector); ++ case NV_50: ++ return nv50_backlight_init(connector); ++ default: ++ break; ++ } + } + ++ + return 0; + } + +-void nouveau_backlight_exit(struct drm_connector *connector) ++void ++nouveau_backlight_exit(struct drm_device *dev) + { +- struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->backlight) { +diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c +index b311fab..032a820 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bios.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bios.c +@@ -296,6 +296,11 @@ munge_reg(struct nvbios *bios, uint32_t reg) + if (dev_priv->card_type < NV_50) + return reg; + ++ if (reg & 0x80000000) { ++ BUG_ON(bios->display.crtc < 0); ++ reg += bios->display.crtc * 0x800; ++ } ++ + if (reg & 0x40000000) { + BUG_ON(!dcbent); + +@@ -304,7 +309,7 @@ munge_reg(struct nvbios *bios, uint32_t reg) + reg += 0x00000080; + } + +- reg &= ~0x60000000; ++ reg &= ~0xe0000000; + return reg; + } + +@@ -1174,22 +1179,19 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * + */ + +- struct bit_displayport_encoder_table *dpe = NULL; + struct dcb_entry *dcb = bios->display.output; + struct drm_device *dev = bios->dev; + uint8_t cond = bios->data[offset + 1]; +- int dummy; ++ uint8_t *table, *entry; + + BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); + + if (!iexec->execute) + return 3; + +- dpe = nouveau_bios_dp_table(dev, dcb, &dummy); +- if (!dpe) { +- NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); ++ table = nouveau_dp_bios_data(dev, dcb, &entry); ++ if (!table) + return 3; +- } + + switch (cond) { + case 0: +@@ -1203,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + break; + case 1: + case 2: +- if (!(dpe->unknown & cond)) ++ if (!(entry[5] & cond)) + iexec->execute = false; + break; + case 5: +@@ -3221,6 +3223,49 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + return 1; + } + ++static void ++init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio) ++{ ++ const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; ++ u32 r, s, v; ++ ++ /* Not a clue, needs de-magicing */ ++ r = nv50_gpio_ctl[gpio->line >> 4]; ++ s = (gpio->line & 0x0f); ++ v = bios_rd32(bios, r) & ~(0x00010001 << s); ++ switch ((gpio->entry & 0x06000000) >> 25) { ++ case 1: ++ v |= (0x00000001 << s); ++ break; ++ case 2: ++ v |= (0x00010000 << s); ++ break; ++ default: ++ break; ++ } ++ ++ bios_wr32(bios, r, v); ++} ++ ++static void ++init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio) ++{ ++ u32 v, i; ++ ++ v = bios_rd32(bios, 0x00d610 + (gpio->line * 4)); ++ v &= 0xffffff00; ++ v |= (gpio->entry & 0x00ff0000) >> 16; ++ bios_wr32(bios, 0x00d610 + (gpio->line * 4), v); ++ ++ i = (gpio->entry & 0x1f000000) >> 24; ++ if (i) { ++ v = bios_rd32(bios, 0x00d640 + ((i - 1) * 4)); ++ v &= 0xffffff00; ++ v |= gpio->line; ++ bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v); ++ } ++} ++ + static int + init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + { +@@ -3235,7 +3280,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; +- const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; + int i; + + if (dev_priv->card_type < NV_50) { +@@ -3248,33 +3292,20 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + + for (i = 0; i < bios->dcb.gpio.entries; i++) { + struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; +- uint32_t r, s, v; + + BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); + + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); +- if (bios->execute) +- pgpio->set(bios->dev, gpio->tag, gpio->state_default); + +- /* The NVIDIA binary driver doesn't appear to actually do +- * any of this, my VBIOS does however. +- */ +- /* Not a clue, needs de-magicing */ +- r = nv50_gpio_ctl[gpio->line >> 4]; +- s = (gpio->line & 0x0f); +- v = bios_rd32(bios, r) & ~(0x00010001 << s); +- switch ((gpio->entry & 0x06000000) >> 25) { +- case 1: +- v |= (0x00000001 << s); +- break; +- case 2: +- v |= (0x00010000 << s); +- break; +- default: +- break; +- } +- bios_wr32(bios, r, v); ++ if (!bios->execute) ++ continue; ++ ++ pgpio->set(bios->dev, gpio->tag, gpio->state_default); ++ if (dev_priv->card_type < NV_D0) ++ init_gpio_unknv50(bios, gpio); ++ else ++ init_gpio_unknvd0(bios, gpio); + } + + return 1; +@@ -3737,6 +3768,10 @@ parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + int count = 0, i, ret; + uint8_t id; + ++ /* catch NULL script pointers */ ++ if (offset == 0) ++ return 0; ++ + /* + * Loop until INIT_DONE causes us to break out of the loop + * (or until offset > bios length just in case... ) +@@ -4389,86 +4424,37 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b + return 0; + } + +-static uint8_t * +-bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, +- uint16_t record, int record_len, int record_nr, +- bool match_link) ++/* BIT 'U'/'d' table encoder subtables have hashes matching them to ++ * a particular set of encoders. ++ * ++ * This function returns true if a particular DCB entry matches. ++ */ ++bool ++bios_encoder_match(struct dcb_entry *dcb, u32 hash) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvbios *bios = &dev_priv->vbios; +- uint32_t entry; +- uint16_t table; +- int i, v; ++ if ((hash & 0x000000f0) != (dcb->location << 4)) ++ return false; ++ if ((hash & 0x0000000f) != dcb->type) ++ return false; ++ if (!(hash & (dcb->or << 16))) ++ return false; + +- switch (dcbent->type) { ++ switch (dcb->type) { + case OUTPUT_TMDS: + case OUTPUT_LVDS: + case OUTPUT_DP: +- break; +- default: +- match_link = false; +- break; +- } +- +- for (i = 0; i < record_nr; i++, record += record_len) { +- table = ROM16(bios->data[record]); +- if (!table) +- continue; +- entry = ROM32(bios->data[table]); +- +- if (match_link) { +- v = (entry & 0x00c00000) >> 22; +- if (!(v & dcbent->sorconf.link)) +- continue; ++ if (hash & 0x00c00000) { ++ if (!(hash & (dcb->sorconf.link << 22))) ++ return false; + } +- +- v = (entry & 0x000f0000) >> 16; +- if (!(v & dcbent->or)) +- continue; +- +- v = (entry & 0x000000f0) >> 4; +- if (v != dcbent->location) +- continue; +- +- v = (entry & 0x0000000f); +- if (v != dcbent->type) +- continue; +- +- return &bios->data[table]; +- } +- +- return NULL; +-} +- +-void * +-nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent, +- int *length) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nvbios *bios = &dev_priv->vbios; +- uint8_t *table; +- +- if (!bios->display.dp_table_ptr) { +- NV_ERROR(dev, "No pointer to DisplayPort table\n"); +- return NULL; +- } +- table = &bios->data[bios->display.dp_table_ptr]; +- +- if (table[0] != 0x20 && table[0] != 0x21) { +- NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n", +- table[0]); +- return NULL; ++ default: ++ return true; + } +- +- *length = table[4]; +- return bios_output_config_match(dev, dcbent, +- bios->display.dp_table_ptr + table[1], +- table[2], table[3], table[0] >= 0x21); + } + + int +-nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, +- uint32_t sub, int pxclk) ++nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, ++ struct dcb_entry *dcbent, int crtc) + { + /* + * The display script table is located by the BIT 'U' table. +@@ -4498,7 +4484,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + uint8_t *table = &bios->data[bios->display.script_table_ptr]; + uint8_t *otable = NULL; + uint16_t script; +- int i = 0; ++ int i; + + if (!bios->display.script_table_ptr) { + NV_ERROR(dev, "No pointer to output script table\n"); +@@ -4550,30 +4536,33 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + + NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n", + dcbent->type, dcbent->location, dcbent->or); +- otable = bios_output_config_match(dev, dcbent, table[1] + +- bios->display.script_table_ptr, +- table[2], table[3], table[0] >= 0x21); ++ for (i = 0; i < table[3]; i++) { ++ otable = ROMPTR(bios, table[table[1] + (i * table[2])]); ++ if (otable && bios_encoder_match(dcbent, ROM32(otable[0]))) ++ break; ++ } ++ + if (!otable) { + NV_DEBUG_KMS(dev, "failed to match any output table\n"); + return 1; + } + +- if (pxclk < -2 || pxclk > 0) { ++ if (pclk < -2 || pclk > 0) { + /* Try to find matching script table entry */ + for (i = 0; i < otable[5]; i++) { +- if (ROM16(otable[table[4] + i*6]) == sub) ++ if (ROM16(otable[table[4] + i*6]) == type) + break; + } + + if (i == otable[5]) { + NV_ERROR(dev, "Table 0x%04x not found for %d/%d, " + "using first\n", +- sub, dcbent->type, dcbent->or); ++ type, dcbent->type, dcbent->or); + i = 0; + } + } + +- if (pxclk == 0) { ++ if (pclk == 0) { + script = ROM16(otable[6]); + if (!script) { + NV_DEBUG_KMS(dev, "output script 0 not found\n"); +@@ -4581,9 +4570,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk == -1) { ++ if (pclk == -1) { + script = ROM16(otable[8]); + if (!script) { + NV_DEBUG_KMS(dev, "output script 1 not found\n"); +@@ -4591,9 +4580,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk == -2) { ++ if (pclk == -2) { + if (table[4] >= 12) + script = ROM16(otable[10]); + else +@@ -4604,31 +4593,31 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk > 0) { ++ if (pclk > 0) { + script = ROM16(otable[table[4] + i*6 + 2]); + if (script) +- script = clkcmptable(bios, script, pxclk); ++ script = clkcmptable(bios, script, pclk); + if (!script) { + NV_DEBUG_KMS(dev, "clock script 0 not found\n"); + return 1; + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk < 0) { ++ if (pclk < 0) { + script = ROM16(otable[table[4] + i*6 + 4]); + if (script) +- script = clkcmptable(bios, script, -pxclk); ++ script = clkcmptable(bios, script, -pclk); + if (!script) { + NV_DEBUG_KMS(dev, "clock script 1 not found\n"); + return 1; + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } + + return 0; +@@ -5478,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios, + return 0; + } + +-static int +-parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios, +- struct bit_entry *bitentry) +-{ +- bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]); +- return 0; +-} +- + struct bit_table { + const char id; + int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); +@@ -5559,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) + parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds)); + parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds)); + parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U)); +- parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport)); + + return 0; + } +@@ -5884,9 +5864,15 @@ parse_dcb_gpio_table(struct nvbios *bios) + } + + e->line = (e->entry & 0x0000001f) >> 0; +- e->state_default = (e->entry & 0x01000000) >> 24; +- e->state[0] = (e->entry & 0x18000000) >> 27; +- e->state[1] = (e->entry & 0x60000000) >> 29; ++ if (gpio[0] == 0x40) { ++ e->state_default = (e->entry & 0x01000000) >> 24; ++ e->state[0] = (e->entry & 0x18000000) >> 27; ++ e->state[1] = (e->entry & 0x60000000) >> 29; ++ } else { ++ e->state_default = (e->entry & 0x00000080) >> 7; ++ e->state[0] = (entry[4] >> 4) & 3; ++ e->state[1] = (entry[4] >> 6) & 3; ++ } + } + } + +@@ -6156,7 +6142,14 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, + } + case OUTPUT_DP: + entry->dpconf.sor.link = (conf & 0x00000030) >> 4; +- entry->dpconf.link_bw = (conf & 0x00e00000) >> 21; ++ switch ((conf & 0x00e00000) >> 21) { ++ case 0: ++ entry->dpconf.link_bw = 162000; ++ break; ++ default: ++ entry->dpconf.link_bw = 270000; ++ break; ++ } + switch ((conf & 0x0f000000) >> 24) { + case 0xf: + entry->dpconf.link_nr = 4; +@@ -6769,7 +6762,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) + + void + nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, +- struct dcb_entry *dcbent) ++ struct dcb_entry *dcbent, int crtc) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; +@@ -6777,11 +6770,22 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, + + spin_lock_bh(&bios->lock); + bios->display.output = dcbent; ++ bios->display.crtc = crtc; + parse_init_table(bios, table, &iexec); + bios->display.output = NULL; + spin_unlock_bh(&bios->lock); + } + ++void ++nouveau_bios_init_exec(struct drm_device *dev, uint16_t table) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvbios *bios = &dev_priv->vbios; ++ struct init_exec iexec = { true, false }; ++ ++ parse_init_table(bios, table, &iexec); ++} ++ + static bool NVInitVBIOS(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -6863,9 +6867,8 @@ nouveau_run_vbios_init(struct drm_device *dev) + + if (dev_priv->card_type >= NV_50) { + for (i = 0; i < bios->dcb.entries; i++) { +- nouveau_bios_run_display_table(dev, +- &bios->dcb.entry[i], +- 0, 0); ++ nouveau_bios_run_display_table(dev, 0, 0, ++ &bios->dcb.entry[i], -1); + } + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h +index 050c314..8adb69e 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bios.h ++++ b/drivers/gpu/drm/nouveau/nouveau_bios.h +@@ -289,8 +289,8 @@ struct nvbios { + + struct { + struct dcb_entry *output; ++ int crtc; + uint16_t script_table_ptr; +- uint16_t dp_table_ptr; + } display; + + struct { +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 890d50e..7226f41 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -956,7 +956,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) + break; + } + +- if (dev_priv->card_type == NV_C0) ++ if (dev_priv->card_type >= NV_C0) + page_shift = node->page_shift; + else + page_shift = 12; +diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c +index 0e3241c..bb6ec9e 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_channel.c ++++ b/drivers/gpu/drm/nouveau/nouveau_channel.c +@@ -412,13 +412,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, + return ret; + init->channel = chan->id; + +- if (chan->dma.ib_max) +- init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | +- NOUVEAU_GEM_DOMAIN_GART; +- else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) ++ if (nouveau_vram_pushbuf == 0) { ++ if (chan->dma.ib_max) ++ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | ++ NOUVEAU_GEM_DOMAIN_GART; ++ else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) ++ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; ++ else ++ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; ++ } else { + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; +- else +- init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; ++ } + + if (dev_priv->card_type < NV_C0) { + init->subchan[0].handle = NvM2MF; +diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c +index 939d4df..e0d275e 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_connector.c ++++ b/drivers/gpu/drm/nouveau/nouveau_connector.c +@@ -39,7 +39,7 @@ + + static void nouveau_connector_hotplug(void *, int); + +-static struct nouveau_encoder * ++struct nouveau_encoder * + find_encoder(struct drm_connector *connector, int type) + { + struct drm_device *dev = connector->dev; +@@ -116,10 +116,6 @@ nouveau_connector_destroy(struct drm_connector *connector) + nouveau_connector_hotplug, connector); + } + +- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || +- connector->connector_type == DRM_MODE_CONNECTOR_eDP) +- nouveau_backlight_exit(connector); +- + kfree(nv_connector->edid); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +@@ -712,11 +708,8 @@ nouveau_connector_mode_valid(struct drm_connector *connector, + case OUTPUT_TV: + return get_slave_funcs(encoder)->mode_valid(encoder, mode); + case OUTPUT_DP: +- if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) +- max_clock = nv_encoder->dp.link_nr * 270000; +- else +- max_clock = nv_encoder->dp.link_nr * 162000; +- ++ max_clock = nv_encoder->dp.link_nr; ++ max_clock *= nv_encoder->dp.link_bw; + clock = clock * nouveau_connector_bpp(connector) / 8; + break; + default: +@@ -871,7 +864,6 @@ nouveau_connector_create(struct drm_device *dev, int index) + dev->mode_config.scaling_mode_property, + nv_connector->scaling_mode); + } +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; + /* fall-through */ + case DCB_CONNECTOR_TV_0: + case DCB_CONNECTOR_TV_1: +@@ -888,27 +880,20 @@ nouveau_connector_create(struct drm_device *dev, int index) + dev->mode_config.dithering_mode_property, + nv_connector->use_dithering ? + DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); +- +- if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) { +- if (dev_priv->card_type >= NV_50) +- connector->polled = DRM_CONNECTOR_POLL_HPD; +- else +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; +- } + break; + } + +- if (pgpio->irq_register) { ++ if (nv_connector->dcb->gpio_tag != 0xff && pgpio->irq_register) { + pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, + nouveau_connector_hotplug, connector); ++ ++ connector->polled = DRM_CONNECTOR_POLL_HPD; ++ } else { ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } + + drm_sysfs_connector_add(connector); + +- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || +- connector->connector_type == DRM_MODE_CONNECTOR_eDP) +- nouveau_backlight_init(connector); +- + dcb->drm = connector; + return dcb->drm; + +@@ -925,22 +910,13 @@ nouveau_connector_hotplug(void *data, int plugged) + struct drm_connector *connector = data; + struct drm_device *dev = connector->dev; + +- NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", +- drm_get_connector_name(connector)); +- +- if (connector->encoder && connector->encoder->crtc && +- connector->encoder->crtc->enabled) { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder); +- struct drm_encoder_helper_funcs *helper = +- connector->encoder->helper_private; ++ NV_DEBUG(dev, "%splugged %s\n", plugged ? "" : "un", ++ drm_get_connector_name(connector)); + +- if (nv_encoder->dcb->type == OUTPUT_DP) { +- if (plugged) +- helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); +- else +- helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); +- } +- } ++ if (plugged) ++ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); ++ else ++ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + + drm_helper_hpd_irq_event(dev); + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h +index cb1ce2a..bf8e128 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h ++++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h +@@ -82,14 +82,13 @@ static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) + } + + int nv50_crtc_create(struct drm_device *dev, int index); +-int nv50_cursor_init(struct nouveau_crtc *); +-void nv50_cursor_fini(struct nouveau_crtc *); + int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file_priv, + uint32_t buffer_handle, uint32_t width, + uint32_t height); + int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y); + + int nv04_cursor_init(struct nouveau_crtc *); ++int nv50_cursor_init(struct nouveau_crtc *); + + struct nouveau_connector * + nouveau_crtc_connector_get(struct nouveau_crtc *crtc); +diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c +index eb514ea..ddbabef 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_display.c ++++ b/drivers/gpu/drm/nouveau/nouveau_display.c +@@ -105,9 +105,12 @@ nouveau_framebuffer_init(struct drm_device *dev, + if (dev_priv->chipset == 0x50) + nv_fb->r_format |= (tile_flags << 8); + +- if (!tile_flags) +- nv_fb->r_pitch = 0x00100000 | fb->pitch; +- else { ++ if (!tile_flags) { ++ if (dev_priv->card_type < NV_D0) ++ nv_fb->r_pitch = 0x00100000 | fb->pitch; ++ else ++ nv_fb->r_pitch = 0x01000000 | fb->pitch; ++ } else { + u32 mode = nvbo->tile_mode; + if (dev_priv->card_type >= NV_C0) + mode >>= 4; +diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c +index 7beb82a..de5efe7 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dp.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dp.c +@@ -28,557 +28,669 @@ + #include "nouveau_i2c.h" + #include "nouveau_connector.h" + #include "nouveau_encoder.h" ++#include "nouveau_crtc.h" + +-static int +-auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) +-{ +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct nouveau_i2c_chan *auxch; +- int ret; ++/****************************************************************************** ++ * aux channel util functions ++ *****************************************************************************/ ++#define AUX_DBG(fmt, args...) do { \ ++ if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \ ++ NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \ ++ } \ ++} while (0) ++#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args) + +- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); +- if (!auxch) +- return -ENODEV; +- +- ret = nouveau_dp_auxch(auxch, 9, address, buf, size); +- if (ret) +- return ret; +- +- return 0; ++static void ++auxch_fini(struct drm_device *dev, int ch) ++{ ++ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); + } + + static int +-auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size) ++auxch_init(struct drm_device *dev, int ch) + { +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct nouveau_i2c_chan *auxch; +- int ret; ++ const u32 unksel = 1; /* nfi which to use, or if it matters.. */ ++ const u32 ureq = unksel ? 0x00100000 : 0x00200000; ++ const u32 urep = unksel ? 0x01000000 : 0x02000000; ++ u32 ctrl, timeout; + +- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); +- if (!auxch) +- return -ENODEV; ++ /* wait up to 1ms for any previous transaction to be done... */ ++ timeout = 1000; ++ do { ++ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); ++ udelay(1); ++ if (!timeout--) { ++ AUX_ERR("begin idle timeout 0x%08x", ctrl); ++ return -EBUSY; ++ } ++ } while (ctrl & 0x03010000); + +- ret = nouveau_dp_auxch(auxch, 8, address, buf, size); +- return ret; ++ /* set some magic, and wait up to 1ms for it to appear */ ++ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); ++ timeout = 1000; ++ do { ++ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); ++ udelay(1); ++ if (!timeout--) { ++ AUX_ERR("magic wait 0x%08x\n", ctrl); ++ auxch_fini(dev, ch); ++ return -EBUSY; ++ } ++ } while ((ctrl & 0x03000000) != urep); ++ ++ return 0; + } + + static int +-nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) ++auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size) + { +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- uint32_t tmp; +- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); ++ u32 ctrl, stat, timeout, retries; ++ u32 xbuf[4] = {}; ++ int ret, i; + +- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); +- tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED | +- NV50_SOR_DP_CTRL_LANE_MASK); +- tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16; +- if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN) +- tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED; +- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); ++ AUX_DBG("%d: 0x%08x %d\n", type, addr, size); + +- return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1); +-} ++ ret = auxch_init(dev, ch); ++ if (ret) ++ goto out; + +-static int +-nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd) +-{ +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- uint32_t tmp; +- int reg = 0x614300 + (nv_encoder->or * 0x800); ++ stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50)); ++ if (!(stat & 0x10000000)) { ++ AUX_DBG("sink not detected\n"); ++ ret = -ENXIO; ++ goto out; ++ } + +- tmp = nv_rd32(dev, reg); +- tmp &= 0xfff3ffff; +- if (cmd == DP_LINK_BW_2_7) +- tmp |= 0x00040000; +- nv_wr32(dev, reg, tmp); ++ if (!(type & 1)) { ++ memcpy(xbuf, data, size); ++ for (i = 0; i < 16; i += 4) { ++ AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); ++ nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); ++ } ++ } + +- return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1); +-} ++ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); ++ ctrl &= ~0x0001f0ff; ++ ctrl |= type << 12; ++ ctrl |= size - 1; ++ nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr); + +-static int +-nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern) +-{ +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- uint32_t tmp; +- uint8_t cmd; +- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); +- int ret; ++ /* retry transaction a number of times on failure... */ ++ ret = -EREMOTEIO; ++ for (retries = 0; retries < 32; retries++) { ++ /* reset, and delay a while if this is a retry */ ++ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); ++ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); ++ if (retries) ++ udelay(400); + +- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); +- tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN; +- tmp |= (pattern << 24); +- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); ++ /* transaction request, wait up to 1ms for it to complete */ ++ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); + +- ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); +- if (ret) +- return ret; +- cmd &= ~DP_TRAINING_PATTERN_MASK; +- cmd |= (pattern & DP_TRAINING_PATTERN_MASK); +- return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); +-} ++ timeout = 1000; ++ do { ++ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); ++ udelay(1); ++ if (!timeout--) { ++ AUX_ERR("tx req timeout 0x%08x\n", ctrl); ++ goto out; ++ } ++ } while (ctrl & 0x00010000); + +-static int +-nouveau_dp_max_voltage_swing(struct drm_encoder *encoder) +-{ +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct drm_device *dev = encoder->dev; +- struct bit_displayport_encoder_table_entry *dpse; +- struct bit_displayport_encoder_table *dpe; +- int i, dpe_headerlen, max_vs = 0; ++ /* read status, and check if transaction completed ok */ ++ stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0); ++ if (!(stat & 0x000f0f00)) { ++ ret = 0; ++ break; ++ } + +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) +- return false; +- dpse = (void *)((char *)dpe + dpe_headerlen); ++ AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); ++ } + +- for (i = 0; i < dpe_headerlen; i++, dpse++) { +- if (dpse->vs_level > max_vs) +- max_vs = dpse->vs_level; ++ if (type & 1) { ++ for (i = 0; i < 16; i += 4) { ++ xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i); ++ AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); ++ } ++ memcpy(data, xbuf, size); + } + +- return max_vs; ++out: ++ auxch_fini(dev, ch); ++ return ret; + } + +-static int +-nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs) ++static u32 ++dp_link_bw_get(struct drm_device *dev, int or, int link) + { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct drm_device *dev = encoder->dev; +- struct bit_displayport_encoder_table_entry *dpse; +- struct bit_displayport_encoder_table *dpe; +- int i, dpe_headerlen, max_pre = 0; +- +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) +- return false; +- dpse = (void *)((char *)dpe + dpe_headerlen); +- +- for (i = 0; i < dpe_headerlen; i++, dpse++) { +- if (dpse->vs_level != vs) +- continue; ++ u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800)); ++ if (!(ctrl & 0x000c0000)) ++ return 162000; ++ return 270000; ++} + +- if (dpse->pre_level > max_pre) +- max_pre = dpse->pre_level; ++static int ++dp_lane_count_get(struct drm_device *dev, int or, int link) ++{ ++ u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); ++ switch (ctrl & 0x000f0000) { ++ case 0x00010000: return 1; ++ case 0x00030000: return 2; ++ default: ++ return 4; + } +- +- return max_pre; + } + +-static bool +-nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) ++void ++nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp) + { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct drm_device *dev = encoder->dev; +- struct bit_displayport_encoder_table *dpe; +- int ret, i, dpe_headerlen, vs = 0, pre = 0; +- uint8_t request[2]; ++ const u32 symbol = 100000; ++ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; ++ int TU, VTUi, VTUf, VTUa; ++ u64 link_data_rate, link_ratio, unk; ++ u32 best_diff = 64 * symbol; ++ u32 link_nr, link_bw, r; + +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) +- return false; ++ /* calculate packed data rate for each lane */ ++ link_nr = dp_lane_count_get(dev, or, link); ++ link_data_rate = (clk * bpp / 8) / link_nr; + +- ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); +- if (ret) +- return false; ++ /* calculate ratio of packed data rate to link symbol rate */ ++ link_bw = dp_link_bw_get(dev, or, link); ++ link_ratio = link_data_rate * symbol; ++ r = do_div(link_ratio, link_bw); + +- NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]); ++ for (TU = 64; TU >= 32; TU--) { ++ /* calculate average number of valid symbols in each TU */ ++ u32 tu_valid = link_ratio * TU; ++ u32 calc, diff; + +- /* Keep all lanes at the same level.. */ +- for (i = 0; i < nv_encoder->dp.link_nr; i++) { +- int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf; +- int lane_vs = lane_req & 3; +- int lane_pre = (lane_req >> 2) & 3; ++ /* find a hw representation for the fraction.. */ ++ VTUi = tu_valid / symbol; ++ calc = VTUi * symbol; ++ diff = tu_valid - calc; ++ if (diff) { ++ if (diff >= (symbol / 2)) { ++ VTUf = symbol / (symbol - diff); ++ if (symbol - (VTUf * diff)) ++ VTUf++; + +- if (lane_vs > vs) +- vs = lane_vs; +- if (lane_pre > pre) +- pre = lane_pre; +- } ++ if (VTUf <= 15) { ++ VTUa = 1; ++ calc += symbol - (symbol / VTUf); ++ } else { ++ VTUa = 0; ++ VTUf = 1; ++ calc += symbol; ++ } ++ } else { ++ VTUa = 0; ++ VTUf = min((int)(symbol / diff), 15); ++ calc += symbol / VTUf; ++ } + +- if (vs >= nouveau_dp_max_voltage_swing(encoder)) { +- vs = nouveau_dp_max_voltage_swing(encoder); +- vs |= 4; ++ diff = calc - tu_valid; ++ } else { ++ /* no remainder, but the hw doesn't like the fractional ++ * part to be zero. decrement the integer part and ++ * have the fraction add a whole symbol back ++ */ ++ VTUa = 0; ++ VTUf = 1; ++ VTUi--; ++ } ++ ++ if (diff < best_diff) { ++ best_diff = diff; ++ bestTU = TU; ++ bestVTUa = VTUa; ++ bestVTUf = VTUf; ++ bestVTUi = VTUi; ++ if (diff == 0) ++ break; ++ } + } + +- if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) { +- pre = nouveau_dp_max_pre_emphasis(encoder, vs & 3); +- pre |= 4; ++ if (!bestTU) { ++ NV_ERROR(dev, "DP: unable to find suitable config\n"); ++ return; + } + +- /* Update the configuration for all lanes.. */ +- for (i = 0; i < nv_encoder->dp.link_nr; i++) +- config[i] = (pre << 3) | vs; ++ /* XXX close to vbios numbers, but not right */ ++ unk = (symbol - link_ratio) * bestTU; ++ unk *= link_ratio; ++ r = do_div(unk, symbol); ++ r = do_div(unk, symbol); ++ unk += 6; + +- return true; ++ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2); ++ nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 | ++ bestVTUf << 16 | ++ bestVTUi << 8 | ++ unk); + } + +-static bool +-nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config) ++u8 * ++nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) + { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct drm_device *dev = encoder->dev; +- struct bit_displayport_encoder_table_entry *dpse; +- struct bit_displayport_encoder_table *dpe; +- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); +- int dpe_headerlen, ret, i; +- +- NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n", +- config[0], config[1], config[2], config[3]); ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvbios *bios = &dev_priv->vbios; ++ struct bit_entry d; ++ u8 *table; ++ int i; + +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) +- return false; +- dpse = (void *)((char *)dpe + dpe_headerlen); ++ if (bit_table(dev, 'd', &d)) { ++ NV_ERROR(dev, "BIT 'd' table not found\n"); ++ return NULL; ++ } + +- for (i = 0; i < dpe->record_nr; i++, dpse++) { +- if (dpse->vs_level == (config[0] & 3) && +- dpse->pre_level == ((config[0] >> 3) & 3)) +- break; ++ if (d.version != 1) { ++ NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version); ++ return NULL; + } +- BUG_ON(i == dpe->record_nr); + +- for (i = 0; i < nv_encoder->dp.link_nr; i++) { +- const int shift[4] = { 16, 8, 0, 24 }; +- uint32_t mask = 0xff << shift[i]; +- uint32_t reg0, reg1, reg2; ++ table = ROMPTR(bios, d.data[0]); ++ if (!table) { ++ NV_ERROR(dev, "displayport table pointer invalid\n"); ++ return NULL; ++ } + +- reg0 = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask; +- reg0 |= (dpse->reg0 << shift[i]); +- reg1 = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask; +- reg1 |= (dpse->reg1 << shift[i]); +- reg2 = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff; +- reg2 |= (dpse->reg2 << 8); +- nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0); +- nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1); +- nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2); ++ switch (table[0]) { ++ case 0x20: ++ case 0x21: ++ case 0x30: ++ break; ++ default: ++ NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]); ++ return NULL; + } + +- ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4); +- if (ret) +- return false; ++ for (i = 0; i < table[3]; i++) { ++ *entry = ROMPTR(bios, table[table[1] + (i * table[2])]); ++ if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0]))) ++ return table; ++ } + +- return true; ++ NV_ERROR(dev, "displayport encoder table not found\n"); ++ return NULL; + } + +-bool +-nouveau_dp_link_train(struct drm_encoder *encoder) ++/****************************************************************************** ++ * link training ++ *****************************************************************************/ ++struct dp_state { ++ struct dcb_entry *dcb; ++ u8 *table; ++ u8 *entry; ++ int auxch; ++ int crtc; ++ int or; ++ int link; ++ u8 *dpcd; ++ int link_nr; ++ u32 link_bw; ++ u8 stat[6]; ++ u8 conf[4]; ++}; ++ ++static void ++dp_set_link_config(struct drm_device *dev, struct dp_state *dp) + { +- struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct nouveau_connector *nv_connector; +- struct bit_displayport_encoder_table *dpe; +- int dpe_headerlen; +- uint8_t config[4], status[3]; +- bool cr_done, cr_max_vs, eq_done, hpd_state; +- int ret = 0, i, tries, voltage; ++ int or = dp->or, link = dp->link; ++ u8 *entry, sink[2]; ++ u32 dp_ctrl; ++ u16 script; + +- NV_DEBUG_KMS(dev, "link training!!\n"); ++ NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); + +- nv_connector = nouveau_encoder_connector_get(nv_encoder); +- if (!nv_connector) +- return false; +- +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) { +- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); +- return false; ++ /* set selected link rate on source */ ++ switch (dp->link_bw) { ++ case 270000: ++ nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000); ++ sink[0] = DP_LINK_BW_2_7; ++ break; ++ default: ++ nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000); ++ sink[0] = DP_LINK_BW_1_62; ++ break; + } + +- /* disable hotplug detect, this flips around on some panels during +- * link training. ++ /* offset +0x0a of each dp encoder table entry is a pointer to another ++ * table, that has (among other things) pointers to more scripts that ++ * need to be executed, this time depending on link speed. + */ +- hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); ++ entry = ROMPTR(&dev_priv->vbios, dp->entry[10]); ++ if (entry) { ++ if (dp->table[0] < 0x30) { ++ while (dp->link_bw < (ROM16(entry[0]) * 10)) ++ entry += 4; ++ script = ROM16(entry[2]); ++ } else { ++ while (dp->link_bw < (entry[0] * 27000)) ++ entry += 3; ++ script = ROM16(entry[1]); ++ } + +- if (dpe->script0) { +- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); +- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), +- nv_encoder->dcb); ++ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); + } + +-train: +- cr_done = eq_done = false; ++ /* configure lane count on the source */ ++ dp_ctrl = ((1 << dp->link_nr) - 1) << 16; ++ sink[1] = dp->link_nr; ++ if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) { ++ dp_ctrl |= 0x00004000; ++ sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; ++ } + +- /* set link configuration */ +- NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n", +- nv_encoder->dp.link_bw, nv_encoder->dp.link_nr); ++ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl); + +- ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw); +- if (ret) +- return false; ++ /* inform the sink of the new configuration */ ++ auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2); ++} + +- config[0] = nv_encoder->dp.link_nr; +- if (nv_encoder->dp.dpcd_version >= 0x11 && +- nv_encoder->dp.enhanced_frame) +- config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; ++static void ++dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp) ++{ ++ u8 sink_tp; + +- ret = nouveau_dp_lane_count_set(encoder, config[0]); +- if (ret) +- return false; ++ NV_DEBUG_KMS(dev, "training pattern %d\n", tp); + +- /* clock recovery */ +- NV_DEBUG_KMS(dev, "\tbegin cr\n"); +- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1); +- if (ret) +- goto stop; ++ nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24); + +- tries = 0; +- voltage = -1; +- memset(config, 0x00, sizeof(config)); +- for (;;) { +- if (!nouveau_dp_link_train_commit(encoder, config)) +- break; ++ auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1); ++ sink_tp &= ~DP_TRAINING_PATTERN_MASK; ++ sink_tp |= tp; ++ auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1); ++} + +- udelay(100); ++static const u8 nv50_lane_map[] = { 16, 8, 0, 24 }; ++static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 }; + +- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2); +- if (ret) +- break; +- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", +- status[0], status[1]); ++static int ++dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 mask = 0, drv = 0, pre = 0, unk = 0; ++ const u8 *shifts; ++ int link = dp->link; ++ int or = dp->or; ++ int i; + +- cr_done = true; +- cr_max_vs = false; +- for (i = 0; i < nv_encoder->dp.link_nr; i++) { +- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; ++ if (dev_priv->chipset != 0xaf) ++ shifts = nv50_lane_map; ++ else ++ shifts = nvaf_lane_map; + +- if (!(lane & DP_LANE_CR_DONE)) { +- cr_done = false; +- if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED) +- cr_max_vs = true; +- break; ++ for (i = 0; i < dp->link_nr; i++) { ++ u8 *conf = dp->entry + dp->table[4]; ++ u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; ++ u8 lpre = (lane & 0x0c) >> 2; ++ u8 lvsw = (lane & 0x03) >> 0; ++ ++ mask |= 0xff << shifts[i]; ++ unk |= 1 << (shifts[i] >> 3); ++ ++ dp->conf[i] = (lpre << 3) | lvsw; ++ if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) ++ dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; ++ if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5) ++ dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; ++ ++ NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]); ++ ++ if (dp->table[0] < 0x30) { ++ u8 *last = conf + (dp->entry[4] * dp->table[5]); ++ while (lvsw != conf[0] || lpre != conf[1]) { ++ conf += dp->table[5]; ++ if (conf >= last) ++ return -EINVAL; + } +- } + +- if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { +- voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK; +- tries = 0; +- } ++ conf += 2; ++ } else { ++ /* no lookup table anymore, set entries for each ++ * combination of voltage swing and pre-emphasis ++ * level allowed by the DP spec. ++ */ ++ switch (lvsw) { ++ case 0: lpre += 0; break; ++ case 1: lpre += 4; break; ++ case 2: lpre += 7; break; ++ case 3: lpre += 9; break; ++ } + +- if (cr_done || cr_max_vs || (++tries == 5)) +- break; ++ conf = conf + (lpre * dp->table[5]); ++ conf++; ++ } + +- if (!nouveau_dp_link_train_adjust(encoder, config)) +- break; ++ drv |= conf[0] << shifts[i]; ++ pre |= conf[1] << shifts[i]; ++ unk = (unk & ~0x0000ff00) | (conf[2] << 8); + } + +- if (!cr_done) +- goto stop; ++ nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv); ++ nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre); ++ nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk); ++ ++ return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4); ++} ++ ++static int ++dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay) ++{ ++ int ret; ++ ++ udelay(delay); + +- /* channel equalisation */ +- NV_DEBUG_KMS(dev, "\tbegin eq\n"); +- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2); ++ ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6); + if (ret) +- goto stop; ++ return ret; + +- for (tries = 0; tries <= 5; tries++) { +- udelay(400); ++ NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n", ++ dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3], ++ dp->stat[4], dp->stat[5]); ++ return 0; ++} + +- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3); +- if (ret) +- break; +- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", +- status[0], status[1]); ++static int ++dp_link_train_cr(struct drm_device *dev, struct dp_state *dp) ++{ ++ bool cr_done = false, abort = false; ++ int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; ++ int tries = 0, i; + +- eq_done = true; +- if (!(status[2] & DP_INTERLANE_ALIGN_DONE)) +- eq_done = false; ++ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1); + +- for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) { +- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; ++ do { ++ if (dp_link_train_commit(dev, dp) || ++ dp_link_train_update(dev, dp, 100)) ++ break; + ++ cr_done = true; ++ for (i = 0; i < dp->link_nr; i++) { ++ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; + if (!(lane & DP_LANE_CR_DONE)) { + cr_done = false; ++ if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED) ++ abort = true; + break; + } ++ } + +- if (!(lane & DP_LANE_CHANNEL_EQ_DONE) || +- !(lane & DP_LANE_SYMBOL_LOCKED)) { +- eq_done = false; +- break; +- } ++ if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { ++ voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; ++ tries = 0; + } ++ } while (!cr_done && !abort && ++tries < 5); + +- if (eq_done || !cr_done) +- break; ++ return cr_done ? 0 : -1; ++} + +- if (!nouveau_dp_link_train_adjust(encoder, config) || +- !nouveau_dp_link_train_commit(encoder, config)) +- break; +- } ++static int ++dp_link_train_eq(struct drm_device *dev, struct dp_state *dp) ++{ ++ bool eq_done, cr_done = true; ++ int tries = 0, i; + +-stop: +- /* end link training */ +- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_DISABLE); +- if (ret) +- return false; ++ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2); + +- /* retry at a lower setting, if possible */ +- if (!ret && !(eq_done && cr_done)) { +- NV_DEBUG_KMS(dev, "\twe failed\n"); +- if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) { +- NV_DEBUG_KMS(dev, "retry link training at low rate\n"); +- nv_encoder->dp.link_bw = DP_LINK_BW_1_62; +- goto train; +- } +- } ++ do { ++ if (dp_link_train_update(dev, dp, 400)) ++ break; + +- if (dpe->script1) { +- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); +- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), +- nv_encoder->dcb); +- } ++ eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE); ++ for (i = 0; i < dp->link_nr && eq_done; i++) { ++ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; ++ if (!(lane & DP_LANE_CR_DONE)) ++ cr_done = false; ++ if (!(lane & DP_LANE_CHANNEL_EQ_DONE) || ++ !(lane & DP_LANE_SYMBOL_LOCKED)) ++ eq_done = false; ++ } + +- /* re-enable hotplug detect */ +- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state); ++ if (dp_link_train_commit(dev, dp)) ++ break; ++ } while (!eq_done && cr_done && ++tries <= 5); + +- return eq_done; ++ return eq_done ? 0 : -1; + } + + bool +-nouveau_dp_detect(struct drm_encoder *encoder) ++nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) + { ++ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; ++ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); ++ struct nouveau_connector *nv_connector = ++ nouveau_encoder_connector_get(nv_encoder); + struct drm_device *dev = encoder->dev; +- uint8_t dpcd[4]; +- int ret; ++ struct nouveau_i2c_chan *auxch; ++ const u32 bw_list[] = { 270000, 162000, 0 }; ++ const u32 *link_bw = bw_list; ++ struct dp_state dp; + +- ret = auxch_rd(encoder, 0x0000, dpcd, 4); +- if (ret) ++ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); ++ if (!auxch) + return false; + +- NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n" +- "display: link_bw %d, link_nr %d version 0x%02x\n", +- nv_encoder->dcb->dpconf.link_bw, +- nv_encoder->dcb->dpconf.link_nr, +- dpcd[1], dpcd[2] & 0x0f, dpcd[0]); ++ dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry); ++ if (!dp.table) ++ return -EINVAL; + +- nv_encoder->dp.dpcd_version = dpcd[0]; ++ dp.dcb = nv_encoder->dcb; ++ dp.crtc = nv_crtc->index; ++ dp.auxch = auxch->rd; ++ dp.or = nv_encoder->or; ++ dp.link = !(nv_encoder->dcb->sorconf.link & 1); ++ dp.dpcd = nv_encoder->dp.dpcd; + +- nv_encoder->dp.link_bw = dpcd[1]; +- if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62 && +- !nv_encoder->dcb->dpconf.link_bw) +- nv_encoder->dp.link_bw = DP_LINK_BW_1_62; ++ /* some sinks toggle hotplug in response to some of the actions ++ * we take during link training (DP_SET_POWER is one), we need ++ * to ignore them for the moment to avoid races. ++ */ ++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); + +- nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; +- if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr) +- nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; ++ /* enable down-spreading, if possible */ ++ if (dp.table[1] >= 16) { ++ u16 script = ROM16(dp.entry[14]); ++ if (nv_encoder->dp.dpcd[3] & 1) ++ script = ROM16(dp.entry[12]); + +- nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP); ++ nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc); ++ } + +- return true; +-} ++ /* execute pre-train script from vbios */ ++ nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc); + +-int +-nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, +- uint8_t *data, int data_nr) +-{ +- struct drm_device *dev = auxch->dev; +- uint32_t tmp, ctrl, stat = 0, data32[4] = {}; +- int ret = 0, i, index = auxch->rd; ++ /* start off at highest link rate supported by encoder and display */ ++ while (*link_bw > nv_encoder->dp.link_bw) ++ link_bw++; + +- NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr); ++ while (link_bw[0]) { ++ /* find minimum required lane count at this link rate */ ++ dp.link_nr = nv_encoder->dp.link_nr; ++ while ((dp.link_nr >> 1) * link_bw[0] > datarate) ++ dp.link_nr >>= 1; + +- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); +- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000); +- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); +- if (!(tmp & 0x01000000)) { +- NV_ERROR(dev, "expected bit 24 == 1, got 0x%08x\n", tmp); +- ret = -EIO; +- goto out; +- } ++ /* drop link rate to minimum with this lane count */ ++ while ((link_bw[1] * dp.link_nr) > datarate) ++ link_bw++; ++ dp.link_bw = link_bw[0]; ++ ++ /* program selected link configuration */ ++ dp_set_link_config(dev, &dp); + +- for (i = 0; i < 3; i++) { +- tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd)); +- if (tmp & NV50_AUXCH_STAT_STATE_READY) ++ /* attempt to train the link at this configuration */ ++ memset(dp.stat, 0x00, sizeof(dp.stat)); ++ if (!dp_link_train_cr(dev, &dp) && ++ !dp_link_train_eq(dev, &dp)) + break; +- udelay(100); +- } + +- if (i == 3) { +- ret = -EBUSY; +- goto out; ++ /* retry at lower rate */ ++ link_bw++; + } + +- if (!(cmd & 1)) { +- memcpy(data32, data, data_nr); +- for (i = 0; i < 4; i++) { +- NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]); +- nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]); +- } +- } ++ /* finish link training */ ++ dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE); + +- nv_wr32(dev, NV50_AUXCH_ADDR(index), addr); +- ctrl = nv_rd32(dev, NV50_AUXCH_CTRL(index)); +- ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN); +- ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT); +- ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT); ++ /* execute post-train script from vbios */ ++ nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc); + +- for (i = 0; i < 16; i++) { +- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); +- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); +- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); +- if (!nv_wait(dev, NV50_AUXCH_CTRL(index), +- 0x00010000, 0x00000000)) { +- NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", +- nv_rd32(dev, NV50_AUXCH_CTRL(index))); +- ret = -EBUSY; +- goto out; +- } ++ /* re-enable hotplug detect */ ++ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); ++ return true; ++} ++ ++bool ++nouveau_dp_detect(struct drm_encoder *encoder) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ struct nouveau_i2c_chan *auxch; ++ u8 *dpcd = nv_encoder->dp.dpcd; ++ int ret; + +- udelay(400); ++ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); ++ if (!auxch) ++ return false; + +- stat = nv_rd32(dev, NV50_AUXCH_STAT(index)); +- if ((stat & NV50_AUXCH_STAT_REPLY_AUX) != +- NV50_AUXCH_STAT_REPLY_AUX_DEFER) +- break; +- } ++ ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8); ++ if (ret) ++ return false; + +- if (i == 16) { +- NV_ERROR(dev, "auxch DEFER too many times, bailing\n"); +- ret = -EREMOTEIO; +- goto out; +- } ++ nv_encoder->dp.link_bw = 27000 * dpcd[1]; ++ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; + +- if (cmd & 1) { +- if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { +- ret = -EREMOTEIO; +- goto out; +- } ++ NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n", ++ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]); ++ NV_DEBUG_KMS(dev, "encoder: %dx%d\n", ++ nv_encoder->dcb->dpconf.link_nr, ++ nv_encoder->dcb->dpconf.link_bw); + +- for (i = 0; i < 4; i++) { +- data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); +- NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); +- } +- memcpy(data, data32, data_nr); +- } ++ if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) ++ nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; ++ if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) ++ nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; + +-out: +- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); +- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000); +- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); +- if (tmp & 0x01000000) { +- NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp); +- ret = -EIO; +- } ++ NV_DEBUG_KMS(dev, "maximum: %dx%d\n", ++ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); + +- udelay(400); ++ return true; ++} + +- return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); ++int ++nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, ++ uint8_t *data, int data_nr) ++{ ++ return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr); + } + + static int + nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + { + struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; +- struct drm_device *dev = auxch->dev; + struct i2c_msg *msg = msgs; + int ret, mcnt = num; + +@@ -602,19 +714,6 @@ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + if (ret < 0) + return ret; + +- switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { +- case NV50_AUXCH_STAT_REPLY_I2C_ACK: +- break; +- case NV50_AUXCH_STAT_REPLY_I2C_NACK: +- return -EREMOTEIO; +- case NV50_AUXCH_STAT_REPLY_I2C_DEFER: +- udelay(100); +- continue; +- default: +- NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); +- return -EREMOTEIO; +- } +- + ptr += cnt; + remaining -= cnt; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c +index b30ddd8..c1e01f3 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.c +@@ -41,7 +41,7 @@ int nouveau_agpmode = -1; + module_param_named(agpmode, nouveau_agpmode, int, 0400); + + MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); +-static int nouveau_modeset = -1; /* kms */ ++int nouveau_modeset = -1; + module_param_named(modeset, nouveau_modeset, int, 0400); + + MODULE_PARM_DESC(vbios, "Override default VBIOS location"); +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h +index d7d51de..29837da 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -414,12 +414,13 @@ struct nouveau_gpio_engine { + }; + + struct nouveau_pm_voltage_level { +- u8 voltage; +- u8 vid; ++ u32 voltage; /* microvolts */ ++ u8 vid; + }; + + struct nouveau_pm_voltage { + bool supported; ++ u8 version; + u8 vid_mask; + + struct nouveau_pm_voltage_level *level; +@@ -428,17 +429,48 @@ struct nouveau_pm_voltage { + + struct nouveau_pm_memtiming { + int id; +- u32 reg_100220; +- u32 reg_100224; +- u32 reg_100228; +- u32 reg_10022c; +- u32 reg_100230; +- u32 reg_100234; +- u32 reg_100238; +- u32 reg_10023c; +- u32 reg_100240; ++ u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */ ++ u32 reg_1; ++ u32 reg_2; ++ u32 reg_3; ++ u32 reg_4; ++ u32 reg_5; ++ u32 reg_6; ++ u32 reg_7; ++ u32 reg_8; ++ /* To be written to 0x1002c0 */ ++ u8 CL; ++ u8 WR; + }; + ++struct nouveau_pm_tbl_header{ ++ u8 version; ++ u8 header_len; ++ u8 entry_cnt; ++ u8 entry_len; ++}; ++ ++struct nouveau_pm_tbl_entry{ ++ u8 tWR; ++ u8 tUNK_1; ++ u8 tCL; ++ u8 tRP; /* Byte 3 */ ++ u8 empty_4; ++ u8 tRAS; /* Byte 5 */ ++ u8 empty_6; ++ u8 tRFC; /* Byte 7 */ ++ u8 empty_8; ++ u8 tRC; /* Byte 9 */ ++ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; ++ u8 empty_15,empty_16,empty_17; ++ u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; ++}; ++ ++/* nouveau_mem.c */ ++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing); ++ + #define NOUVEAU_PM_MAX_LEVEL 8 + struct nouveau_pm_level { + struct device_attribute dev_attr; +@@ -448,11 +480,19 @@ struct nouveau_pm_level { + u32 core; + u32 memory; + u32 shader; +- u32 unk05; +- u32 unk0a; ++ u32 rop; ++ u32 copy; ++ u32 daemon; ++ u32 vdec; ++ u32 unk05; /* nv50:nva3, roughly.. */ ++ u32 unka0; /* nva3:nvc0 */ ++ u32 hub01; /* nvc0- */ ++ u32 hub06; /* nvc0- */ ++ u32 hub07; /* nvc0- */ + +- u8 voltage; +- u8 fanspeed; ++ u32 volt_min; /* microvolts */ ++ u32 volt_max; ++ u8 fanspeed; + + u16 memscript; + struct nouveau_pm_memtiming *timing; +@@ -496,6 +536,11 @@ struct nouveau_pm_engine { + void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, + u32 id, int khz); + void (*clock_set)(struct drm_device *, void *); ++ ++ int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); ++ void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); ++ void (*clocks_set)(struct drm_device *, void *); ++ + int (*voltage_get)(struct drm_device *); + int (*voltage_set)(struct drm_device *, int voltage); + int (*fanspeed_get)(struct drm_device *); +@@ -504,7 +549,7 @@ struct nouveau_pm_engine { + }; + + struct nouveau_vram_engine { +- struct nouveau_mm *mm; ++ struct nouveau_mm mm; + + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *dev); +@@ -623,6 +668,7 @@ enum nouveau_card_type { + NV_40 = 0x40, + NV_50 = 0x50, + NV_C0 = 0xc0, ++ NV_D0 = 0xd0 + }; + + struct drm_nouveau_private { +@@ -633,8 +679,8 @@ struct drm_nouveau_private { + enum nouveau_card_type card_type; + /* exact chipset, derived from NV_PMC_BOOT_0 */ + int chipset; +- int stepping; + int flags; ++ u32 crystal; + + void __iomem *mmio; + +@@ -721,7 +767,6 @@ struct drm_nouveau_private { + uint64_t vram_size; + uint64_t vram_sys_base; + +- uint64_t fb_phys; + uint64_t fb_available_size; + uint64_t fb_mappable_pages; + uint64_t fb_aper_free; +@@ -784,6 +829,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) + } + + /* nouveau_drv.c */ ++extern int nouveau_modeset; + extern int nouveau_agpmode; + extern int nouveau_duallink; + extern int nouveau_uscript_lvds; +@@ -824,6 +870,8 @@ extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val); + extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val); ++extern bool nouveau_wait_cb(struct drm_device *, u64 timeout, ++ bool (*cond)(void *), void *); + extern bool nouveau_wait_for_idle(struct drm_device *); + extern int nouveau_card_init(struct drm_device *); + +@@ -1006,15 +1054,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector + + /* nouveau_backlight.c */ + #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT +-extern int nouveau_backlight_init(struct drm_connector *); +-extern void nouveau_backlight_exit(struct drm_connector *); ++extern int nouveau_backlight_init(struct drm_device *); ++extern void nouveau_backlight_exit(struct drm_device *); + #else +-static inline int nouveau_backlight_init(struct drm_connector *dev) ++static inline int nouveau_backlight_init(struct drm_device *dev) + { + return 0; + } + +-static inline void nouveau_backlight_exit(struct drm_connector *dev) { } ++static inline void nouveau_backlight_exit(struct drm_device *dev) { } + #endif + + /* nouveau_bios.c */ +@@ -1022,7 +1070,8 @@ extern int nouveau_bios_init(struct drm_device *); + extern void nouveau_bios_takedown(struct drm_device *dev); + extern int nouveau_run_vbios_init(struct drm_device *); + extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, +- struct dcb_entry *); ++ struct dcb_entry *, int crtc); ++extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table); + extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *, + enum dcb_gpio_tag); + extern struct dcb_connector_table_entry * +@@ -1030,11 +1079,8 @@ nouveau_bios_connector_entry(struct drm_device *, int index); + extern u32 get_pll_register(struct drm_device *, enum pll_types); + extern int get_pll_limits(struct drm_device *, uint32_t limit_match, + struct pll_lims *); +-extern int nouveau_bios_run_display_table(struct drm_device *, +- struct dcb_entry *, +- uint32_t script, int pxclk); +-extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *, +- int *length); ++extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, ++ struct dcb_entry *, int crtc); + extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); + extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *); + extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk, +@@ -1043,6 +1089,7 @@ extern int run_tmds_table(struct drm_device *, struct dcb_entry *, + int head, int pxclk); + extern int call_lvds_script(struct drm_device *, struct dcb_entry *, int head, + enum LVDS_script, int pxclk); ++bool bios_encoder_match(struct dcb_entry *, u32 hash); + + /* nouveau_ttm.c */ + int nouveau_ttm_global_init(struct drm_nouveau_private *); +@@ -1053,7 +1100,9 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *); + int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, + uint8_t *data, int data_nr); + bool nouveau_dp_detect(struct drm_encoder *); +-bool nouveau_dp_link_train(struct drm_encoder *); ++bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate); ++void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32); ++u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **); + + /* nv04_fb.c */ + extern int nv04_fb_init(struct drm_device *); +@@ -1179,8 +1228,8 @@ extern int nva3_copy_create(struct drm_device *dev); + /* nvc0_copy.c */ + extern int nvc0_copy_create(struct drm_device *dev, int engine); + +-/* nv40_mpeg.c */ +-extern int nv40_mpeg_create(struct drm_device *dev); ++/* nv31_mpeg.c */ ++extern int nv31_mpeg_create(struct drm_device *dev); + + /* nv50_mpeg.c */ + extern int nv50_mpeg_create(struct drm_device *dev); +@@ -1265,6 +1314,11 @@ extern int nv04_display_create(struct drm_device *); + extern int nv04_display_init(struct drm_device *); + extern void nv04_display_destroy(struct drm_device *); + ++/* nvd0_display.c */ ++extern int nvd0_display_create(struct drm_device *); ++extern int nvd0_display_init(struct drm_device *); ++extern void nvd0_display_destroy(struct drm_device *); ++ + /* nv04_crtc.c */ + extern int nv04_crtc_create(struct drm_device *, int index); + +@@ -1374,6 +1428,8 @@ int nv50_gpio_init(struct drm_device *dev); + void nv50_gpio_fini(struct drm_device *dev); + int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); + int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); ++int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); ++int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); + int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, + void (*)(void *, int), void *); + void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, +@@ -1448,6 +1504,8 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) + nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) + #define nv_wait_ne(dev, reg, mask, val) \ + nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) ++#define nv_wait_cb(dev, func, data) \ ++ nouveau_wait_cb(dev, 2000000000ULL, (func), (data)) + + /* PRAMIN access */ + static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) +@@ -1514,6 +1572,7 @@ enum { + NOUVEAU_REG_DEBUG_RMVIO = 0x80, + NOUVEAU_REG_DEBUG_VGAATTR = 0x100, + NOUVEAU_REG_DEBUG_EVO = 0x200, ++ NOUVEAU_REG_DEBUG_AUXCH = 0x400 + }; + + #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \ +diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h +index ae69b61..e5d6e3f 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h ++++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h +@@ -49,17 +49,17 @@ struct nouveau_encoder { + + union { + struct { +- int mc_unknown; +- uint32_t unk0; +- uint32_t unk1; +- int dpcd_version; ++ u8 dpcd[8]; + int link_nr; + int link_bw; +- bool enhanced_frame; ++ u32 datarate; + } dp; + }; + }; + ++struct nouveau_encoder * ++find_encoder(struct drm_connector *connector, int type); ++ + static inline struct nouveau_encoder *nouveau_encoder(struct drm_encoder *enc) + { + struct drm_encoder_slave *slave = to_encoder_slave(enc); +@@ -83,21 +83,4 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder); + int nv50_sor_create(struct drm_connector *, struct dcb_entry *); + int nv50_dac_create(struct drm_connector *, struct dcb_entry *); + +-struct bit_displayport_encoder_table { +- uint32_t match; +- uint8_t record_nr; +- uint8_t unknown; +- uint16_t script0; +- uint16_t script1; +- uint16_t unknown_table; +-} __attribute__ ((packed)); +- +-struct bit_displayport_encoder_table_entry { +- uint8_t vs_level; +- uint8_t pre_level; +- uint8_t reg0; +- uint8_t reg1; +- uint8_t reg2; +-} __attribute__ ((packed)); +- + #endif /* __NOUVEAU_ENCODER_H__ */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index ae22dfa..2f6daae 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -519,7 +519,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) + if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { + struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; + +- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, ++ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY, + mem->start << PAGE_SHIFT, + mem->size, NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VRAM, &obj); +diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c +index cb389d0..f6a27fa 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c ++++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c +@@ -107,6 +107,13 @@ nv4e_i2c_getsda(void *data) + return !!((nv_rd32(dev, i2c->rd) >> 16) & 8); + } + ++static const uint32_t nv50_i2c_port[] = { ++ 0x00e138, 0x00e150, 0x00e168, 0x00e180, ++ 0x00e254, 0x00e274, 0x00e764, 0x00e780, ++ 0x00e79c, 0x00e7b8 ++}; ++#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) ++ + static int + nv50_i2c_getscl(void *data) + { +@@ -130,28 +137,32 @@ static void + nv50_i2c_setscl(void *data, int state) + { + struct nouveau_i2c_chan *i2c = data; +- struct drm_device *dev = i2c->dev; + +- nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); ++ nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); + } + + static void + nv50_i2c_setsda(void *data, int state) + { + struct nouveau_i2c_chan *i2c = data; +- struct drm_device *dev = i2c->dev; + +- nv_wr32(dev, i2c->wr, +- (nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0)); ++ nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0)); + i2c->data = state; + } + +-static const uint32_t nv50_i2c_port[] = { +- 0x00e138, 0x00e150, 0x00e168, 0x00e180, +- 0x00e254, 0x00e274, 0x00e764, 0x00e780, +- 0x00e79c, 0x00e7b8 +-}; +-#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) ++static int ++nvd0_i2c_getscl(void *data) ++{ ++ struct nouveau_i2c_chan *i2c = data; ++ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10); ++} ++ ++static int ++nvd0_i2c_getsda(void *data) ++{ ++ struct nouveau_i2c_chan *i2c = data; ++ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20); ++} + + int + nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) +@@ -163,7 +174,8 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) + if (entry->chan) + return -EEXIST; + +- if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { ++ if (dev_priv->card_type >= NV_50 && ++ dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) { + NV_ERROR(dev, "unknown i2c port %d\n", entry->read); + return -EINVAL; + } +@@ -192,10 +204,17 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) + case 5: + i2c->bit.setsda = nv50_i2c_setsda; + i2c->bit.setscl = nv50_i2c_setscl; +- i2c->bit.getsda = nv50_i2c_getsda; +- i2c->bit.getscl = nv50_i2c_getscl; +- i2c->rd = nv50_i2c_port[entry->read]; +- i2c->wr = i2c->rd; ++ if (dev_priv->card_type < NV_D0) { ++ i2c->bit.getsda = nv50_i2c_getsda; ++ i2c->bit.getscl = nv50_i2c_getscl; ++ i2c->rd = nv50_i2c_port[entry->read]; ++ i2c->wr = i2c->rd; ++ } else { ++ i2c->bit.getsda = nvd0_i2c_getsda; ++ i2c->bit.getscl = nvd0_i2c_getscl; ++ i2c->rd = 0x00d014 + (entry->read * 0x20); ++ i2c->wr = i2c->rd; ++ } + break; + case 6: + i2c->rd = entry->read; +@@ -267,7 +286,10 @@ nouveau_i2c_find(struct drm_device *dev, int index) + val = 0xe001; + } + +- nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val); ++ /* nfi, but neither auxch or i2c work if it's 1 */ ++ nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000); ++ /* nfi, but switches auxch vs normal i2c */ ++ nv_mask(dev, reg + 0x00, 0x0000f003, val); + } + + if (!i2c->chan && nouveau_i2c_init(dev, i2c, index)) +diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c +index f9ae2fc..36bec48 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_mem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c +@@ -408,8 +408,6 @@ nouveau_mem_vram_init(struct drm_device *dev) + if (ret) + return ret; + +- dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); +- + ret = nouveau_ttm_global_init(dev_priv); + if (ret) + return ret; +@@ -504,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev) + return 0; + } + ++/* XXX: For now a dummy. More samples required, possibly even a card ++ * Called from nouveau_perf.c */ ++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing) { ++ ++ NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); ++} ++ ++void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing) { ++ ++ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); ++ ++ /* XXX: I don't trust the -1's and +1's... they must come ++ * from somewhere! */ ++ timing->reg_1 = (e->tWR + 2 + magic_number) << 24 | ++ 1 << 16 | ++ (e->tUNK_1 + 2 + magic_number) << 8 | ++ (e->tCL + 2 - magic_number); ++ timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); ++ timing->reg_2 |= 0x20200000; ++ ++ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1,timing->reg_2); ++} ++ ++void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ uint8_t unk18 = 1, ++ unk19 = 1, ++ unk20 = 0, ++ unk21 = 0; ++ ++ switch (min(hdr->entry_len, (u8) 22)) { ++ case 22: ++ unk21 = e->tUNK_21; ++ case 21: ++ unk20 = e->tUNK_20; ++ case 20: ++ unk19 = e->tUNK_19; ++ case 19: ++ unk18 = e->tUNK_18; ++ break; ++ } ++ ++ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); ++ ++ /* XXX: I don't trust the -1's and +1's... they must come ++ * from somewhere! */ ++ timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 | ++ max(unk18, (u8) 1) << 16 | ++ (e->tUNK_1 + unk19 + 1 + magic_number) << 8; ++ if (dev_priv->chipset == 0xa8) { ++ timing->reg_1 |= (e->tCL - 1); ++ } else { ++ timing->reg_1 |= (e->tCL + 2 - magic_number); ++ } ++ timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); ++ ++ timing->reg_5 = (e->tRAS << 24 | e->tRC); ++ timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; ++ ++ if (P->version == 1) { ++ timing->reg_2 |= magic_number << 24; ++ timing->reg_3 = (0x14 + e->tCL) << 24 | ++ 0x16 << 16 | ++ (e->tCL - 1) << 8 | ++ (e->tCL - 1); ++ timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; ++ timing->reg_5 |= (e->tCL + 2) << 8; ++ timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16; ++ } else { ++ timing->reg_2 |= (unk19 - 1) << 24; ++ /* XXX: reg_10022c for recentish cards pretty much unknown*/ ++ timing->reg_3 = e->tCL - 1; ++ timing->reg_4 = (unk20 << 24 | unk21 << 16 | ++ e->tUNK_13 << 8 | e->tUNK_13); ++ /* XXX: +6? */ ++ timing->reg_5 |= (unk19 + 6) << 8; ++ ++ /* XXX: reg_10023c currently unknown ++ * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ ++ timing->reg_7 = 0x202; ++ } ++ ++ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1, ++ timing->reg_2, timing->reg_3); ++ NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", ++ timing->reg_4, timing->reg_5, ++ timing->reg_6, timing->reg_7); ++ NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); ++} ++ ++void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { ++ timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); ++ timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f); ++ timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8; ++ timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; ++ timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; ++ NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1, ++ timing->reg_2, timing->reg_3); ++ NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", ++ timing->reg_4, timing->reg_5, ++ timing->reg_6, timing->reg_7); ++} ++ ++/** ++ * Processes the Memory Timing BIOS table, stores generated ++ * register values ++ * @pre init scripts were run, memtiming regs are initialized ++ */ + void + nouveau_mem_timing_init(struct drm_device *dev) + { +- /* cards < NVC0 only */ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm_memtimings *memtimings = &pm->memtimings; + struct nvbios *bios = &dev_priv->vbios; + struct bit_entry P; +- u8 tUNK_0, tUNK_1, tUNK_2; +- u8 tRP; /* Byte 3 */ +- u8 tRAS; /* Byte 5 */ +- u8 tRFC; /* Byte 7 */ +- u8 tRC; /* Byte 9 */ +- u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; +- u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; +- u8 magic_number = 0; /* Yeah... sorry*/ +- u8 *mem = NULL, *entry; +- int i, recordlen, entries; ++ struct nouveau_pm_tbl_header *hdr = NULL; ++ uint8_t magic_number; ++ u8 *entry; ++ int i; + + if (bios->type == NVBIOS_BIT) { + if (bit_table(dev, 'P', &P)) + return; + + if (P.version == 1) +- mem = ROMPTR(bios, P.data[4]); ++ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]); + else + if (P.version == 2) +- mem = ROMPTR(bios, P.data[8]); ++ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]); + else { + NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); + } +@@ -541,150 +650,56 @@ nouveau_mem_timing_init(struct drm_device *dev) + return; + } + +- if (!mem) { ++ if (!hdr) { + NV_DEBUG(dev, "memory timing table pointer invalid\n"); + return; + } + +- if (mem[0] != 0x10) { +- NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]); ++ if (hdr->version != 0x10) { ++ NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); + return; + } + + /* validate record length */ +- entries = mem[2]; +- recordlen = mem[3]; +- if (recordlen < 15) { +- NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]); ++ if (hdr->entry_len < 15) { ++ NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); + return; + } + + /* parse vbios entries into common format */ + memtimings->timing = +- kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); ++ kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); + if (!memtimings->timing) + return; + + /* Get "some number" from the timing reg for NV_40 and NV_50 +- * Used in calculations later */ +- if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { ++ * Used in calculations later... source unknown */ ++ magic_number = 0; ++ if (P.version == 1) { + magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; + } + +- entry = mem + mem[1]; +- for (i = 0; i < entries; i++, entry += recordlen) { ++ entry = (u8*) hdr + hdr->header_len; ++ for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { + struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; + if (entry[0] == 0) + continue; + +- tUNK_18 = 1; +- tUNK_19 = 1; +- tUNK_20 = 0; +- tUNK_21 = 0; +- switch (min(recordlen, 22)) { +- case 22: +- tUNK_21 = entry[21]; +- case 21: +- tUNK_20 = entry[20]; +- case 20: +- tUNK_19 = entry[19]; +- case 19: +- tUNK_18 = entry[18]; +- default: +- tUNK_0 = entry[0]; +- tUNK_1 = entry[1]; +- tUNK_2 = entry[2]; +- tRP = entry[3]; +- tRAS = entry[5]; +- tRFC = entry[7]; +- tRC = entry[9]; +- tUNK_10 = entry[10]; +- tUNK_11 = entry[11]; +- tUNK_12 = entry[12]; +- tUNK_13 = entry[13]; +- tUNK_14 = entry[14]; +- break; +- } +- +- timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP); +- +- /* XXX: I don't trust the -1's and +1's... they must come +- * from somewhere! */ +- timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | +- max(tUNK_18, (u8) 1) << 16 | +- (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; +- if (dev_priv->chipset == 0xa8) { +- timing->reg_100224 |= (tUNK_2 - 1); +- } else { +- timing->reg_100224 |= (tUNK_2 + 2 - magic_number); +- } +- +- timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); +- if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) +- timing->reg_100228 |= (tUNK_19 - 1) << 24; +- else +- timing->reg_100228 |= magic_number << 24; +- +- if (dev_priv->card_type == NV_40) { +- /* NV40: don't know what the rest of the regs are.. +- * And don't need to know either */ +- timing->reg_100228 |= 0x20200000; +- } else if (dev_priv->card_type >= NV_50) { +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_10022c = (0x14 + tUNK_2) << 24 | +- 0x16 << 16 | +- (tUNK_2 - 1) << 8 | +- (tUNK_2 - 1); +- } else { +- /* XXX: reg_10022c for recentish cards */ +- timing->reg_10022c = tUNK_2 - 1; +- } +- +- timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | +- tUNK_13 << 8 | tUNK_13); +- +- timing->reg_100234 = (tRAS << 24 | tRC); +- timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; +- +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_100234 |= (tUNK_2 + 2) << 8; +- } else { +- /* XXX: +6? */ +- timing->reg_100234 |= (tUNK_19 + 6) << 8; +- } +- +- /* XXX; reg_100238 +- * reg_100238: 0x00?????? */ +- timing->reg_10023c = 0x202; +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; +- } else { +- /* XXX: reg_10023c +- * currently unknown +- * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ +- } +- +- /* XXX: reg_100240? */ +- } + timing->id = i; ++ timing->WR = entry[0]; ++ timing->CL = entry[2]; + +- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, +- timing->reg_100220, timing->reg_100224, +- timing->reg_100228, timing->reg_10022c); +- NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", +- timing->reg_100230, timing->reg_100234, +- timing->reg_100238, timing->reg_10023c); +- NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); ++ if(dev_priv->card_type <= NV_40) { ++ nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); ++ } else if(dev_priv->card_type == NV_50){ ++ nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); ++ } else if(dev_priv->card_type == NV_C0) { ++ nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); ++ } + } + +- memtimings->nr_timing = entries; +- memtimings->supported = (dev_priv->chipset <= 0x98); ++ memtimings->nr_timing = hdr->entry_cnt; ++ memtimings->supported = P.version == 1; + } + + void +@@ -693,7 +708,10 @@ nouveau_mem_timing_fini(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; + +- kfree(mem->timing); ++ if(mem->timing) { ++ kfree(mem->timing); ++ mem->timing = NULL; ++ } + } + + static int +diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c +index 1640dec..b29ffb3 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_mm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_mm.c +@@ -27,7 +27,7 @@ + #include "nouveau_mm.h" + + static inline void +-region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) ++region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a) + { + list_del(&a->nl_entry); + list_del(&a->fl_entry); +@@ -35,7 +35,7 @@ region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) + } + + static struct nouveau_mm_node * +-region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) ++region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) + { + struct nouveau_mm_node *b; + +@@ -57,33 +57,33 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) + return b; + } + +-#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ ++#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ + list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) + + void +-nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) ++nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this) + { + struct nouveau_mm_node *prev = node(this, prev); + struct nouveau_mm_node *next = node(this, next); + +- list_add(&this->fl_entry, &rmm->free); ++ list_add(&this->fl_entry, &mm->free); + this->type = 0; + + if (prev && prev->type == 0) { + prev->length += this->length; +- region_put(rmm, this); ++ region_put(mm, this); + this = prev; + } + + if (next && next->type == 0) { + next->offset = this->offset; + next->length += this->length; +- region_put(rmm, this); ++ region_put(mm, this); + } + } + + int +-nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, ++nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc, + u32 align, struct nouveau_mm_node **pnode) + { + struct nouveau_mm_node *prev, *this, *next; +@@ -92,17 +92,17 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, + u32 splitoff; + u32 s, e; + +- list_for_each_entry(this, &rmm->free, fl_entry) { ++ list_for_each_entry(this, &mm->free, fl_entry) { + e = this->offset + this->length; + s = this->offset; + + prev = node(this, prev); + if (prev && prev->type != type) +- s = roundup(s, rmm->block_size); ++ s = roundup(s, mm->block_size); + + next = node(this, next); + if (next && next->type != type) +- e = rounddown(e, rmm->block_size); ++ e = rounddown(e, mm->block_size); + + s = (s + align_mask) & ~align_mask; + e &= ~align_mask; +@@ -110,10 +110,10 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, + continue; + + splitoff = s - this->offset; +- if (splitoff && !region_split(rmm, this, splitoff)) ++ if (splitoff && !region_split(mm, this, splitoff)) + return -ENOMEM; + +- this = region_split(rmm, this, min(size, e - s)); ++ this = region_split(mm, this, min(size, e - s)); + if (!this) + return -ENOMEM; + +@@ -127,52 +127,49 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, + } + + int +-nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) ++nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) + { +- struct nouveau_mm *rmm; +- struct nouveau_mm_node *heap; ++ struct nouveau_mm_node *node; + +- heap = kzalloc(sizeof(*heap), GFP_KERNEL); +- if (!heap) +- return -ENOMEM; +- heap->offset = roundup(offset, block); +- heap->length = rounddown(offset + length, block) - heap->offset; ++ if (block) { ++ mutex_init(&mm->mutex); ++ INIT_LIST_HEAD(&mm->nodes); ++ INIT_LIST_HEAD(&mm->free); ++ mm->block_size = block; ++ mm->heap_nodes = 0; ++ } + +- rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); +- if (!rmm) { +- kfree(heap); ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (!node) + return -ENOMEM; +- } +- rmm->block_size = block; +- mutex_init(&rmm->mutex); +- INIT_LIST_HEAD(&rmm->nodes); +- INIT_LIST_HEAD(&rmm->free); +- list_add(&heap->nl_entry, &rmm->nodes); +- list_add(&heap->fl_entry, &rmm->free); ++ node->offset = roundup(offset, mm->block_size); ++ node->length = rounddown(offset + length, mm->block_size) - node->offset; + +- *prmm = rmm; ++ list_add_tail(&node->nl_entry, &mm->nodes); ++ list_add_tail(&node->fl_entry, &mm->free); ++ mm->heap_nodes++; + return 0; + } + + int +-nouveau_mm_fini(struct nouveau_mm **prmm) ++nouveau_mm_fini(struct nouveau_mm *mm) + { +- struct nouveau_mm *rmm = *prmm; + struct nouveau_mm_node *node, *heap = +- list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry); ++ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry); ++ int nodes = 0; + +- if (!list_is_singular(&rmm->nodes)) { +- printk(KERN_ERR "nouveau_mm not empty at destroy time!\n"); +- list_for_each_entry(node, &rmm->nodes, nl_entry) { +- printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", +- node->type, node->offset, node->length); ++ list_for_each_entry(node, &mm->nodes, nl_entry) { ++ if (nodes++ == mm->heap_nodes) { ++ printk(KERN_ERR "nouveau_mm in use at destroy time!\n"); ++ list_for_each_entry(node, &mm->nodes, nl_entry) { ++ printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", ++ node->type, node->offset, node->length); ++ } ++ WARN_ON(1); ++ return -EBUSY; + } +- WARN_ON(1); +- return -EBUSY; + } + + kfree(heap); +- kfree(rmm); +- *prmm = NULL; + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h +index b9c016d..57a600c 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_mm.h ++++ b/drivers/gpu/drm/nouveau/nouveau_mm.h +@@ -42,10 +42,11 @@ struct nouveau_mm { + struct mutex mutex; + + u32 block_size; ++ int heap_nodes; + }; + +-int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); +-int nouveau_mm_fini(struct nouveau_mm **); ++int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); ++int nouveau_mm_fini(struct nouveau_mm *); + int nouveau_mm_pre(struct nouveau_mm *); + int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc, + u32 align, struct nouveau_mm_node **); +diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c +index 159b7c4..02222c5 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_object.c ++++ b/drivers/gpu/drm/nouveau/nouveau_object.c +@@ -693,6 +693,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + static int + nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) + { ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_device *dev = chan->dev; + struct nouveau_gpuobj *pgd = NULL; + struct nouveau_vm_pgd *vpgd; +@@ -722,6 +723,9 @@ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) + nv_wo32(chan->ramin, 0x020c, 0x000000ff); + + /* map display semaphore buffers into channel's vm */ ++ if (dev_priv->card_type >= NV_D0) ++ return 0; ++ + for (i = 0; i < 2; i++) { + struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; + +@@ -746,7 +750,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + int ret, i; + + NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); +- if (dev_priv->card_type == NV_C0) ++ if (dev_priv->card_type >= NV_C0) + return nvc0_gpuobj_channel_init(chan, vm); + + /* Allocate a chunk of memory for per-channel object storage */ +@@ -793,7 +797,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + return ret; + + /* dma objects for display sync channel semaphore blocks */ +- for (i = 0; i < 2; i++) { ++ for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct nouveau_gpuobj *sem = NULL; + struct nv50_display_crtc *dispc = + &nv50_display(dev)->crtc[i]; +@@ -875,18 +879,18 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- if (dev_priv->card_type >= NV_50) { ++ if (dev_priv->card_type >= NV_50 && dev_priv->card_type <= NV_C0) { + struct nv50_display *disp = nv50_display(dev); + +- for (i = 0; i < 2; i++) { ++ for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct nv50_display_crtc *dispc = &disp->crtc[i]; + nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]); + } +- +- nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); +- nouveau_gpuobj_ref(NULL, &chan->vm_pd); + } + ++ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); ++ nouveau_gpuobj_ref(NULL, &chan->vm_pd); ++ + if (drm_mm_initialized(&chan->ramin_heap)) + drm_mm_takedown(&chan->ramin_heap); + nouveau_gpuobj_ref(NULL, &chan->ramin); +diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c +index ef9dec0..9f178aa 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_perf.c ++++ b/drivers/gpu/drm/nouveau/nouveau_perf.c +@@ -127,13 +127,57 @@ nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P, + + entry += ramcfg * recordlen; + if (entry[1] >= pm->memtimings.nr_timing) { +- NV_WARN(dev, "timingset %d does not exist\n", entry[1]); ++ if (entry[1] != 0xff) ++ NV_WARN(dev, "timingset %d does not exist\n", entry[1]); + return NULL; + } + + return &pm->memtimings.timing[entry[1]]; + } + ++static void ++nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, ++ struct nouveau_pm_level *perflvl) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvbios *bios = &dev_priv->vbios; ++ u8 *vmap; ++ int id; ++ ++ id = perflvl->volt_min; ++ perflvl->volt_min = 0; ++ ++ /* boards using voltage table version <0x40 store the voltage ++ * level directly in the perflvl entry as a multiple of 10mV ++ */ ++ if (dev_priv->engine.pm.voltage.version < 0x40) { ++ perflvl->volt_min = id * 10000; ++ perflvl->volt_max = perflvl->volt_min; ++ return; ++ } ++ ++ /* on newer ones, the perflvl stores an index into yet another ++ * vbios table containing a min/max voltage value for the perflvl ++ */ ++ if (P->version != 2 || P->length < 34) { ++ NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", ++ P->version, P->length); ++ return; ++ } ++ ++ vmap = ROMPTR(bios, P->data[32]); ++ if (!vmap) { ++ NV_DEBUG(dev, "volt map table pointer invalid\n"); ++ return; ++ } ++ ++ if (id < vmap[3]) { ++ vmap += vmap[1] + (vmap[2] * id); ++ perflvl->volt_min = ROM32(vmap[0]); ++ perflvl->volt_max = ROM32(vmap[4]); ++ } ++} ++ + void + nouveau_perf_init(struct drm_device *dev) + { +@@ -141,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev) + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nvbios *bios = &dev_priv->vbios; + struct bit_entry P; ++ struct nouveau_pm_memtimings *memtimings = &pm->memtimings; ++ struct nouveau_pm_tbl_header mt_hdr; + u8 version, headerlen, recordlen, entries; + u8 *perf, *entry; + int vid, i; +@@ -188,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev) + } + + entry = perf + headerlen; ++ ++ /* For version 0x15, initialize memtiming table */ ++ if(version == 0x15) { ++ memtimings->timing = ++ kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); ++ if(!memtimings) { ++ NV_WARN(dev,"Could not allocate memtiming table\n"); ++ return; ++ } ++ ++ mt_hdr.entry_cnt = entries; ++ mt_hdr.entry_len = 14; ++ mt_hdr.version = version; ++ mt_hdr.header_len = 4; ++ } ++ + for (i = 0; i < entries; i++) { + struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; + +@@ -203,7 +265,8 @@ nouveau_perf_init(struct drm_device *dev) + case 0x13: + case 0x15: + perflvl->fanspeed = entry[55]; +- perflvl->voltage = (recordlen > 56) ? entry[56] : 0; ++ if (recordlen > 56) ++ perflvl->volt_min = entry[56]; + perflvl->core = ROM32(entry[1]) * 10; + perflvl->memory = ROM32(entry[5]) * 20; + break; +@@ -211,9 +274,10 @@ nouveau_perf_init(struct drm_device *dev) + case 0x23: + case 0x24: + perflvl->fanspeed = entry[4]; +- perflvl->voltage = entry[5]; +- perflvl->core = ROM16(entry[6]) * 1000; +- ++ perflvl->volt_min = entry[5]; ++ perflvl->shader = ROM16(entry[6]) * 1000; ++ perflvl->core = perflvl->shader; ++ perflvl->core += (signed char)entry[8] * 1000; + if (dev_priv->chipset == 0x49 || + dev_priv->chipset == 0x4b) + perflvl->memory = ROM16(entry[11]) * 1000; +@@ -223,7 +287,7 @@ nouveau_perf_init(struct drm_device *dev) + break; + case 0x25: + perflvl->fanspeed = entry[4]; +- perflvl->voltage = entry[5]; ++ perflvl->volt_min = entry[5]; + perflvl->core = ROM16(entry[6]) * 1000; + perflvl->shader = ROM16(entry[10]) * 1000; + perflvl->memory = ROM16(entry[12]) * 1000; +@@ -232,7 +296,7 @@ nouveau_perf_init(struct drm_device *dev) + perflvl->memscript = ROM16(entry[2]); + case 0x35: + perflvl->fanspeed = entry[6]; +- perflvl->voltage = entry[7]; ++ perflvl->volt_min = entry[7]; + perflvl->core = ROM16(entry[8]) * 1000; + perflvl->shader = ROM16(entry[10]) * 1000; + perflvl->memory = ROM16(entry[12]) * 1000; +@@ -240,30 +304,34 @@ nouveau_perf_init(struct drm_device *dev) + perflvl->unk05 = ROM16(entry[16]) * 1000; + break; + case 0x40: +-#define subent(n) entry[perf[2] + ((n) * perf[3])] ++#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 + perflvl->fanspeed = 0; /*XXX*/ +- perflvl->voltage = entry[2]; ++ perflvl->volt_min = entry[2]; + if (dev_priv->card_type == NV_50) { +- perflvl->core = ROM16(subent(0)) & 0xfff; +- perflvl->shader = ROM16(subent(1)) & 0xfff; +- perflvl->memory = ROM16(subent(2)) & 0xfff; ++ perflvl->core = subent(0); ++ perflvl->shader = subent(1); ++ perflvl->memory = subent(2); ++ perflvl->vdec = subent(3); ++ perflvl->unka0 = subent(4); + } else { +- perflvl->shader = ROM16(subent(3)) & 0xfff; ++ perflvl->hub06 = subent(0); ++ perflvl->hub01 = subent(1); ++ perflvl->copy = subent(2); ++ perflvl->shader = subent(3); ++ perflvl->rop = subent(4); ++ perflvl->memory = subent(5); ++ perflvl->vdec = subent(6); ++ perflvl->daemon = subent(10); ++ perflvl->hub07 = subent(11); + perflvl->core = perflvl->shader / 2; +- perflvl->unk0a = ROM16(subent(4)) & 0xfff; +- perflvl->memory = ROM16(subent(5)) & 0xfff; + } +- +- perflvl->core *= 1000; +- perflvl->shader *= 1000; +- perflvl->memory *= 1000; +- perflvl->unk0a *= 1000; + break; + } + + /* make sure vid is valid */ +- if (pm->voltage.supported && perflvl->voltage) { +- vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); ++ nouveau_perf_voltage(dev, &P, perflvl); ++ if (pm->voltage.supported && perflvl->volt_min) { ++ vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); + if (vid < 0) { + NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); + entry += recordlen; +@@ -272,7 +340,11 @@ nouveau_perf_init(struct drm_device *dev) + } + + /* get the corresponding memory timings */ +- if (version > 0x15) { ++ if (version == 0x15) { ++ memtimings->timing[i].id = i; ++ nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]); ++ perflvl->timing = &memtimings->timing[i]; ++ } else if (version > 0x15) { + /* last 3 args are for < 0x40, ignored for >= 0x40 */ + perflvl->timing = + nouveau_perf_timing(dev, &P, +diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c +index da8d994..a539fd2 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_pm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_pm.c +@@ -64,18 +64,26 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) + if (perflvl == pm->cur) + return 0; + +- if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { +- ret = pm->voltage_set(dev, perflvl->voltage); ++ if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { ++ ret = pm->voltage_set(dev, perflvl->volt_min); + if (ret) { + NV_ERROR(dev, "voltage_set %d failed: %d\n", +- perflvl->voltage, ret); ++ perflvl->volt_min, ret); + } + } + +- nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); +- nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); +- nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); +- nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); ++ if (pm->clocks_pre) { ++ void *state = pm->clocks_pre(dev, perflvl); ++ if (IS_ERR(state)) ++ return PTR_ERR(state); ++ pm->clocks_set(dev, state); ++ } else ++ if (pm->clock_set) { ++ nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); ++ nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); ++ nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); ++ nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); ++ } + + pm->cur = perflvl; + return 0; +@@ -92,9 +100,6 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile) + if (nouveau_perflvl_wr != 7777) + return -EPERM; + +- if (!pm->clock_set) +- return -EINVAL; +- + if (!strncmp(profile, "boot", 4)) + perflvl = &pm->boot; + else { +@@ -123,31 +128,37 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + int ret; + +- if (!pm->clock_get) +- return -EINVAL; +- + memset(perflvl, 0, sizeof(*perflvl)); + +- ret = pm->clock_get(dev, PLL_CORE); +- if (ret > 0) +- perflvl->core = ret; ++ if (pm->clocks_get) { ++ ret = pm->clocks_get(dev, perflvl); ++ if (ret) ++ return ret; ++ } else ++ if (pm->clock_get) { ++ ret = pm->clock_get(dev, PLL_CORE); ++ if (ret > 0) ++ perflvl->core = ret; + +- ret = pm->clock_get(dev, PLL_MEMORY); +- if (ret > 0) +- perflvl->memory = ret; ++ ret = pm->clock_get(dev, PLL_MEMORY); ++ if (ret > 0) ++ perflvl->memory = ret; + +- ret = pm->clock_get(dev, PLL_SHADER); +- if (ret > 0) +- perflvl->shader = ret; ++ ret = pm->clock_get(dev, PLL_SHADER); ++ if (ret > 0) ++ perflvl->shader = ret; + +- ret = pm->clock_get(dev, PLL_UNK05); +- if (ret > 0) +- perflvl->unk05 = ret; ++ ret = pm->clock_get(dev, PLL_UNK05); ++ if (ret > 0) ++ perflvl->unk05 = ret; ++ } + + if (pm->voltage.supported && pm->voltage_get) { + ret = pm->voltage_get(dev); +- if (ret > 0) +- perflvl->voltage = ret; ++ if (ret > 0) { ++ perflvl->volt_min = ret; ++ perflvl->volt_max = ret; ++ } + } + + return 0; +@@ -156,7 +167,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) + static void + nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) + { +- char c[16], s[16], v[16], f[16], t[16]; ++ char c[16], s[16], v[32], f[16], t[16], m[16]; + + c[0] = '\0'; + if (perflvl->core) +@@ -166,9 +177,19 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) + if (perflvl->shader) + snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); + ++ m[0] = '\0'; ++ if (perflvl->memory) ++ snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); ++ + v[0] = '\0'; +- if (perflvl->voltage) +- snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); ++ if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { ++ snprintf(v, sizeof(v), " voltage %dmV-%dmV", ++ perflvl->volt_min / 1000, perflvl->volt_max / 1000); ++ } else ++ if (perflvl->volt_min) { ++ snprintf(v, sizeof(v), " voltage %dmV", ++ perflvl->volt_min / 1000); ++ } + + f[0] = '\0'; + if (perflvl->fanspeed) +@@ -178,8 +199,7 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) + if (perflvl->timing) + snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); + +- snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, +- c, s, v, f, t); ++ snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); + } + + static ssize_t +@@ -190,7 +210,7 @@ nouveau_pm_get_perflvl_info(struct device *d, + char *ptr = buf; + int len = PAGE_SIZE; + +- snprintf(ptr, len, "%d: ", perflvl->id); ++ snprintf(ptr, len, "%d:", perflvl->id); + ptr += strlen(buf); + len -= strlen(buf); + +@@ -211,9 +231,9 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) + if (!pm->cur) + snprintf(ptr, len, "setting: boot\n"); + else if (pm->cur == &pm->boot) +- snprintf(ptr, len, "setting: boot\nc: "); ++ snprintf(ptr, len, "setting: boot\nc:"); + else +- snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); ++ snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); + ptr += strlen(buf); + len -= strlen(buf); + +@@ -292,7 +312,7 @@ nouveau_sysfs_fini(struct drm_device *dev) + } + } + +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + static ssize_t + nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) + { +@@ -409,7 +429,7 @@ static const struct attribute_group hwmon_attrgroup = { + static int + nouveau_hwmon_init(struct drm_device *dev) + { +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct device *hwmon_dev; +@@ -442,7 +462,7 @@ nouveau_hwmon_init(struct drm_device *dev) + static void + nouveau_hwmon_fini(struct drm_device *dev) + { +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + +@@ -488,7 +508,7 @@ nouveau_pm_init(struct drm_device *dev) + NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); + for (i = 0; i < pm->nr_perflvl; i++) { + nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); +- NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); ++ NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); + } + + /* determine current ("boot") performance level */ +@@ -498,7 +518,7 @@ nouveau_pm_init(struct drm_device *dev) + pm->cur = &pm->boot; + + nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); +- NV_INFO(dev, "c: %s", info); ++ NV_INFO(dev, "c:%s", info); + } + + /* switch performance levels now if requested */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h +index 4a9838dd..8ac02cd 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_pm.h ++++ b/drivers/gpu/drm/nouveau/nouveau_pm.h +@@ -52,6 +52,11 @@ void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, + u32 id, int khz); + void nv04_pm_clock_set(struct drm_device *, void *); + ++/* nv40_pm.c */ ++int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); ++void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); ++void nv40_pm_clocks_set(struct drm_device *, void *); ++ + /* nv50_pm.c */ + int nv50_pm_clock_get(struct drm_device *, u32 id); + void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, +@@ -59,10 +64,12 @@ void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, + void nv50_pm_clock_set(struct drm_device *, void *); + + /* nva3_pm.c */ +-int nva3_pm_clock_get(struct drm_device *, u32 id); +-void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, +- u32 id, int khz); +-void nva3_pm_clock_set(struct drm_device *, void *); ++int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); ++void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); ++void nva3_pm_clocks_set(struct drm_device *, void *); ++ ++/* nvc0_pm.c */ ++int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); + + /* nouveau_temp.c */ + void nouveau_temp_init(struct drm_device *dev); +diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h +index f18cdfc..43a96b9 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_reg.h ++++ b/drivers/gpu/drm/nouveau/nouveau_reg.h +@@ -826,9 +826,12 @@ + #define NV50_PDISPLAY_SOR_DPMS_STATE_ACTIVE 0x00030000 + #define NV50_PDISPLAY_SOR_DPMS_STATE_BLANKED 0x00080000 + #define NV50_PDISPLAY_SOR_DPMS_STATE_WAIT 0x10000000 +-#define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084 +-#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 +-#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff ++#define NV50_PDISP_SOR_PWM_DIV(i) (0x0061c080 + (i) * 0x800) ++#define NV50_PDISP_SOR_PWM_CTL(i) (0x0061c084 + (i) * 0x800) ++#define NV50_PDISP_SOR_PWM_CTL_NEW 0x80000000 ++#define NVA3_PDISP_SOR_PWM_CTL_UNK 0x40000000 ++#define NV50_PDISP_SOR_PWM_CTL_VAL 0x000007ff ++#define NVA3_PDISP_SOR_PWM_CTL_VAL 0x00ffffff + #define NV50_SOR_DP_CTRL(i, l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) + #define NV50_SOR_DP_CTRL_ENABLED 0x00000001 + #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 +@@ -843,7 +846,7 @@ + #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000 + #define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) + #define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) +-#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_SCFG(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) + #define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) + + #define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) +diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +index 2706cb3..c8a463b 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +@@ -12,8 +12,8 @@ struct nouveau_sgdma_be { + struct drm_device *dev; + + dma_addr_t *pages; +- bool *ttm_alloced; + unsigned nr_pages; ++ bool unmap_pages; + + u64 offset; + bool bound; +@@ -26,43 +26,28 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_device *dev = nvbe->dev; ++ int i; + + NV_DEBUG(nvbe->dev, "num_pages = %ld\n", num_pages); + +- if (nvbe->pages) +- return -EINVAL; +- +- nvbe->pages = kmalloc(sizeof(dma_addr_t) * num_pages, GFP_KERNEL); +- if (!nvbe->pages) +- return -ENOMEM; ++ nvbe->pages = dma_addrs; ++ nvbe->nr_pages = num_pages; ++ nvbe->unmap_pages = true; + +- nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL); +- if (!nvbe->ttm_alloced) { +- kfree(nvbe->pages); +- nvbe->pages = NULL; +- return -ENOMEM; ++ /* this code path isn't called and is incorrect anyways */ ++ if (0) { /* dma_addrs[0] != DMA_ERROR_CODE) { */ ++ nvbe->unmap_pages = false; ++ return 0; + } + +- nvbe->nr_pages = 0; +- while (num_pages--) { +- /* this code path isn't called and is incorrect anyways */ +- if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ +- nvbe->pages[nvbe->nr_pages] = +- dma_addrs[nvbe->nr_pages]; +- nvbe->ttm_alloced[nvbe->nr_pages] = true; +- } else { +- nvbe->pages[nvbe->nr_pages] = +- pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0, +- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); +- if (pci_dma_mapping_error(dev->pdev, +- nvbe->pages[nvbe->nr_pages])) { +- be->func->clear(be); +- return -EFAULT; +- } +- nvbe->ttm_alloced[nvbe->nr_pages] = false; ++ for (i = 0; i < num_pages; i++) { ++ nvbe->pages[i] = pci_map_page(dev->pdev, pages[i], 0, ++ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ if (pci_dma_mapping_error(dev->pdev, nvbe->pages[i])) { ++ nvbe->nr_pages = --i; ++ be->func->clear(be); ++ return -EFAULT; + } +- +- nvbe->nr_pages++; + } + + return 0; +@@ -72,26 +57,20 @@ static void + nouveau_sgdma_clear(struct ttm_backend *be) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; +- struct drm_device *dev; +- +- if (nvbe && nvbe->pages) { +- dev = nvbe->dev; +- NV_DEBUG(dev, "\n"); ++ struct drm_device *dev = nvbe->dev; + +- if (nvbe->bound) +- be->func->unbind(be); ++ if (nvbe->bound) ++ be->func->unbind(be); + ++ if (nvbe->unmap_pages) { + while (nvbe->nr_pages--) { +- if (!nvbe->ttm_alloced[nvbe->nr_pages]) +- pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], ++ pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + } +- kfree(nvbe->pages); +- kfree(nvbe->ttm_alloced); +- nvbe->pages = NULL; +- nvbe->ttm_alloced = NULL; +- nvbe->nr_pages = 0; ++ nvbe->unmap_pages = false; + } ++ ++ nvbe->pages = NULL; + } + + static void +diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c +index 10656e4..82478e0 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -286,9 +286,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->gpio.get = nv10_gpio_get; + engine->gpio.set = nv10_gpio_set; + engine->gpio.irq_enable = NULL; +- engine->pm.clock_get = nv04_pm_clock_get; +- engine->pm.clock_pre = nv04_pm_clock_pre; +- engine->pm.clock_set = nv04_pm_clock_set; ++ engine->pm.clocks_get = nv40_pm_clocks_get; ++ engine->pm.clocks_pre = nv40_pm_clocks_pre; ++ engine->pm.clocks_set = nv40_pm_clocks_set; + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; + engine->pm.temp_get = nv40_temp_get; +@@ -299,7 +299,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + case 0x50: + case 0x80: /* gotta love NVIDIA's consistency.. */ + case 0x90: +- case 0xA0: ++ case 0xa0: + engine->instmem.init = nv50_instmem_init; + engine->instmem.takedown = nv50_instmem_takedown; + engine->instmem.suspend = nv50_instmem_suspend; +@@ -359,9 +359,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->pm.clock_set = nv50_pm_clock_set; + break; + default: +- engine->pm.clock_get = nva3_pm_clock_get; +- engine->pm.clock_pre = nva3_pm_clock_pre; +- engine->pm.clock_set = nva3_pm_clock_set; ++ engine->pm.clocks_get = nva3_pm_clocks_get; ++ engine->pm.clocks_pre = nva3_pm_clocks_pre; ++ engine->pm.clocks_set = nva3_pm_clocks_set; + break; + } + engine->pm.voltage_get = nouveau_voltage_gpio_get; +@@ -376,7 +376,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nv50_vram_flags_valid; + break; +- case 0xC0: ++ case 0xc0: + engine->instmem.init = nvc0_instmem_init; + engine->instmem.takedown = nvc0_instmem_takedown; + engine->instmem.suspend = nvc0_instmem_suspend; +@@ -422,12 +422,73 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nvc0_vram_flags_valid; + engine->pm.temp_get = nv84_temp_get; ++ engine->pm.clocks_get = nvc0_pm_clocks_get; ++ engine->pm.voltage_get = nouveau_voltage_gpio_get; ++ engine->pm.voltage_set = nouveau_voltage_gpio_set; ++ break; ++ case 0xd0: ++ engine->instmem.init = nvc0_instmem_init; ++ engine->instmem.takedown = nvc0_instmem_takedown; ++ engine->instmem.suspend = nvc0_instmem_suspend; ++ engine->instmem.resume = nvc0_instmem_resume; ++ engine->instmem.get = nv50_instmem_get; ++ engine->instmem.put = nv50_instmem_put; ++ engine->instmem.map = nv50_instmem_map; ++ engine->instmem.unmap = nv50_instmem_unmap; ++ engine->instmem.flush = nv84_instmem_flush; ++ engine->mc.init = nv50_mc_init; ++ engine->mc.takedown = nv50_mc_takedown; ++ engine->timer.init = nv04_timer_init; ++ engine->timer.read = nv04_timer_read; ++ engine->timer.takedown = nv04_timer_takedown; ++ engine->fb.init = nvc0_fb_init; ++ engine->fb.takedown = nvc0_fb_takedown; ++ engine->fifo.channels = 128; ++ engine->fifo.init = nvc0_fifo_init; ++ engine->fifo.takedown = nvc0_fifo_takedown; ++ engine->fifo.disable = nvc0_fifo_disable; ++ engine->fifo.enable = nvc0_fifo_enable; ++ engine->fifo.reassign = nvc0_fifo_reassign; ++ engine->fifo.channel_id = nvc0_fifo_channel_id; ++ engine->fifo.create_context = nvc0_fifo_create_context; ++ engine->fifo.destroy_context = nvc0_fifo_destroy_context; ++ engine->fifo.load_context = nvc0_fifo_load_context; ++ engine->fifo.unload_context = nvc0_fifo_unload_context; ++ engine->display.early_init = nouveau_stub_init; ++ engine->display.late_takedown = nouveau_stub_takedown; ++ engine->display.create = nvd0_display_create; ++ engine->display.init = nvd0_display_init; ++ engine->display.destroy = nvd0_display_destroy; ++ engine->gpio.init = nv50_gpio_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nvd0_gpio_get; ++ engine->gpio.set = nvd0_gpio_set; ++ engine->gpio.irq_register = nv50_gpio_irq_register; ++ engine->gpio.irq_unregister = nv50_gpio_irq_unregister; ++ engine->gpio.irq_enable = nv50_gpio_irq_enable; ++ engine->vram.init = nvc0_vram_init; ++ engine->vram.takedown = nv50_vram_fini; ++ engine->vram.get = nvc0_vram_new; ++ engine->vram.put = nv50_vram_del; ++ engine->vram.flags_valid = nvc0_vram_flags_valid; ++ engine->pm.clocks_get = nvc0_pm_clocks_get; ++ engine->pm.voltage_get = nouveau_voltage_gpio_get; ++ engine->pm.voltage_set = nouveau_voltage_gpio_set; + break; + default: + NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); + return 1; + } + ++ /* headless mode */ ++ if (nouveau_modeset == 2) { ++ engine->display.early_init = nouveau_stub_init; ++ engine->display.late_takedown = nouveau_stub_takedown; ++ engine->display.create = nouveau_stub_init; ++ engine->display.init = nouveau_stub_init; ++ engine->display.destroy = nouveau_stub_takedown; ++ } ++ + return 0; + } + +@@ -449,21 +510,6 @@ nouveau_vga_set_decode(void *priv, bool state) + return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + } + +-static int +-nouveau_card_init_channel(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int ret; +- +- ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, +- NvDmaFB, NvDmaTT); +- if (ret) +- return ret; +- +- mutex_unlock(&dev_priv->channel->mutex); +- return 0; +-} +- + static void nouveau_switcheroo_set_state(struct pci_dev *pdev, + enum vga_switcheroo_state state) + { +@@ -630,8 +676,11 @@ nouveau_card_init(struct drm_device *dev) + break; + } + +- if (dev_priv->card_type == NV_40) +- nv40_mpeg_create(dev); ++ if (dev_priv->card_type == NV_40 || ++ dev_priv->chipset == 0x31 || ++ dev_priv->chipset == 0x34 || ++ dev_priv->chipset == 0x36) ++ nv31_mpeg_create(dev); + else + if (dev_priv->card_type == NV_50 && + (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0)) +@@ -651,41 +700,69 @@ nouveau_card_init(struct drm_device *dev) + goto out_engine; + } + +- ret = engine->display.create(dev); ++ ret = nouveau_irq_init(dev); + if (ret) + goto out_fifo; + +- ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); +- if (ret) +- goto out_vblank; ++ /* initialise general modesetting */ ++ drm_mode_config_init(dev); ++ drm_mode_create_scaling_mode_property(dev); ++ drm_mode_create_dithering_property(dev); ++ dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; ++ dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); ++ dev->mode_config.min_width = 0; ++ dev->mode_config.min_height = 0; ++ if (dev_priv->card_type < NV_10) { ++ dev->mode_config.max_width = 2048; ++ dev->mode_config.max_height = 2048; ++ } else ++ if (dev_priv->card_type < NV_50) { ++ dev->mode_config.max_width = 4096; ++ dev->mode_config.max_height = 4096; ++ } else { ++ dev->mode_config.max_width = 8192; ++ dev->mode_config.max_height = 8192; ++ } + +- ret = nouveau_irq_init(dev); ++ ret = engine->display.create(dev); + if (ret) +- goto out_vblank; ++ goto out_irq; + +- /* what about PVIDEO/PCRTC/PRAMDAC etc? */ ++ nouveau_backlight_init(dev); + + if (dev_priv->eng[NVOBJ_ENGINE_GR]) { + ret = nouveau_fence_init(dev); + if (ret) +- goto out_irq; ++ goto out_disp; + +- ret = nouveau_card_init_channel(dev); ++ ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, ++ NvDmaFB, NvDmaTT); + if (ret) + goto out_fence; ++ ++ mutex_unlock(&dev_priv->channel->mutex); ++ } ++ ++ if (dev->mode_config.num_crtc) { ++ ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ++ if (ret) ++ goto out_chan; ++ ++ nouveau_fbcon_init(dev); ++ drm_kms_helper_poll_init(dev); + } + +- nouveau_fbcon_init(dev); +- drm_kms_helper_poll_init(dev); + return 0; + ++out_chan: ++ nouveau_channel_put_unlocked(&dev_priv->channel); + out_fence: + nouveau_fence_fini(dev); ++out_disp: ++ nouveau_backlight_exit(dev); ++ engine->display.destroy(dev); + out_irq: + nouveau_irq_fini(dev); +-out_vblank: +- drm_vblank_cleanup(dev); +- engine->display.destroy(dev); + out_fifo: + if (!dev_priv->noaccel) + engine->fifo.takedown(dev); +@@ -732,15 +809,20 @@ static void nouveau_card_takedown(struct drm_device *dev) + struct nouveau_engine *engine = &dev_priv->engine; + int e; + +- drm_kms_helper_poll_fini(dev); +- nouveau_fbcon_fini(dev); ++ if (dev->mode_config.num_crtc) { ++ drm_kms_helper_poll_fini(dev); ++ nouveau_fbcon_fini(dev); ++ drm_vblank_cleanup(dev); ++ } + + if (dev_priv->channel) { + nouveau_channel_put_unlocked(&dev_priv->channel); + nouveau_fence_fini(dev); + } + ++ nouveau_backlight_exit(dev); + engine->display.destroy(dev); ++ drm_mode_config_cleanup(dev); + + if (!dev_priv->noaccel) { + engine->fifo.takedown(dev); +@@ -774,7 +856,6 @@ static void nouveau_card_takedown(struct drm_device *dev) + engine->vram.takedown(dev); + + nouveau_irq_fini(dev); +- drm_vblank_cleanup(dev); + + nouveau_pm_fini(dev); + nouveau_bios_takedown(dev); +@@ -907,7 +988,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev) + int nouveau_load(struct drm_device *dev, unsigned long flags) + { + struct drm_nouveau_private *dev_priv; +- uint32_t reg0; ++ uint32_t reg0, strap; + resource_size_t mmio_start_offs; + int ret; + +@@ -951,13 +1032,11 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + + /* Time to determine the card architecture */ + reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); +- dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ + + /* We're dealing with >=NV10 */ + if ((reg0 & 0x0f000000) > 0) { + /* Bit 27-20 contain the architecture in hex */ + dev_priv->chipset = (reg0 & 0xff00000) >> 20; +- dev_priv->stepping = (reg0 & 0xff); + /* NV04 or NV05 */ + } else if ((reg0 & 0xff00fff0) == 0x20004000) { + if (reg0 & 0x00f00000) +@@ -987,6 +1066,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + case 0xc0: + dev_priv->card_type = NV_C0; + break; ++ case 0xd0: ++ dev_priv->card_type = NV_D0; ++ break; + default: + NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); + ret = -EINVAL; +@@ -996,6 +1078,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", + dev_priv->card_type, reg0); + ++ /* determine frequency of timing crystal */ ++ strap = nv_rd32(dev, 0x101000); ++ if ( dev_priv->chipset < 0x17 || ++ (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25)) ++ strap &= 0x00000040; ++ else ++ strap &= 0x00400040; ++ ++ switch (strap) { ++ case 0x00000000: dev_priv->crystal = 13500; break; ++ case 0x00000040: dev_priv->crystal = 14318; break; ++ case 0x00400000: dev_priv->crystal = 27000; break; ++ case 0x00400040: dev_priv->crystal = 25000; break; ++ } ++ ++ NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal); ++ + /* Determine whether we'll attempt acceleration or not, some + * cards are disabled by default here due to them being known + * non-functional, or never been tested due to lack of hw. +@@ -1030,7 +1129,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + ioremap(pci_resource_start(dev->pdev, ramin_bar), + dev_priv->ramin_size); + if (!dev_priv->ramin) { +- NV_ERROR(dev, "Failed to PRAMIN BAR"); ++ NV_ERROR(dev, "Failed to map PRAMIN BAR\n"); + ret = -ENOMEM; + goto err_mmio; + } +@@ -1130,7 +1229,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, + getparam->value = 1; + break; + case NOUVEAU_GETPARAM_HAS_PAGEFLIP: +- getparam->value = 1; ++ getparam->value = dev_priv->card_type < NV_D0; + break; + case NOUVEAU_GETPARAM_GRAPH_UNITS: + /* NV40 and NV50 versions are quite different, but register +@@ -1198,6 +1297,23 @@ nouveau_wait_ne(struct drm_device *dev, uint64_t timeout, + return false; + } + ++/* Wait until cond(data) == true, up until timeout has hit */ ++bool ++nouveau_wait_cb(struct drm_device *dev, u64 timeout, ++ bool (*cond)(void *), void *data) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; ++ u64 start = ptimer->read(dev); ++ ++ do { ++ if (cond(data) == true) ++ return true; ++ } while (ptimer->read(dev) - start < timeout); ++ ++ return false; ++} ++ + /* Waits for PGRAPH to go completely idle */ + bool nouveau_wait_for_idle(struct drm_device *dev) + { +diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c +index 244fd38..ef0832b 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_vm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_vm.c +@@ -172,9 +172,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) + vm->map_pgt(vpgd->obj, pde, vpgt->obj); + } + +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + } + } + +@@ -191,18 +191,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) + pgt_size = (1 << (vm->pgt_bits + 12)) >> type; + pgt_size *= 8; + +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &pgt); +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + if (unlikely(ret)) + return ret; + + /* someone beat us to filling the PDE while we didn't have the lock */ + if (unlikely(vpgt->refcount[big]++)) { +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + return 0; + } + +@@ -223,10 +223,10 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, + u32 fpde, lpde, pde; + int ret; + +- mutex_lock(&vm->mm->mutex); +- ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); ++ mutex_lock(&vm->mm.mutex); ++ ret = nouveau_mm_get(&vm->mm, page_shift, msize, 0, align, &vma->node); + if (unlikely(ret != 0)) { +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + return ret; + } + +@@ -245,13 +245,13 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, + if (ret) { + if (pde != fpde) + nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); +- nouveau_mm_put(vm->mm, vma->node); +- mutex_unlock(&vm->mm->mutex); ++ nouveau_mm_put(&vm->mm, vma->node); ++ mutex_unlock(&vm->mm.mutex); + vma->node = NULL; + return ret; + } + } +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + + vma->vm = vm; + vma->offset = (u64)vma->node->offset << 12; +@@ -270,11 +270,11 @@ nouveau_vm_put(struct nouveau_vma *vma) + fpde = (vma->node->offset >> vm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; + +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde); +- nouveau_mm_put(vm->mm, vma->node); ++ nouveau_mm_put(&vm->mm, vma->node); + vma->node = NULL; +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + } + + int +@@ -306,7 +306,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, + block = length; + + } else +- if (dev_priv->card_type == NV_C0) { ++ if (dev_priv->card_type >= NV_C0) { + vm->map_pgt = nvc0_vm_map_pgt; + vm->map = nvc0_vm_map; + vm->map_sg = nvc0_vm_map_sg; +@@ -360,11 +360,11 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) + + nouveau_gpuobj_ref(pgd, &vpgd->obj); + +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + for (i = vm->fpde; i <= vm->lpde; i++) + vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); + list_add(&vpgd->head, &vm->pgd_list); +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + return 0; + } + +@@ -377,7 +377,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) + if (!mpgd) + return; + +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { + if (vpgd->obj == mpgd) { + pgd = vpgd->obj; +@@ -386,7 +386,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) + break; + } + } +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + + nouveau_gpuobj_ref(NULL, &pgd); + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h +index 579ca8c..6ce995f 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_vm.h ++++ b/drivers/gpu/drm/nouveau/nouveau_vm.h +@@ -51,7 +51,7 @@ struct nouveau_vma { + + struct nouveau_vm { + struct drm_device *dev; +- struct nouveau_mm *mm; ++ struct nouveau_mm mm; + int refcount; + + struct list_head pgd_list; +diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c +index 75e87274..86d03e1 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_volt.c ++++ b/drivers/gpu/drm/nouveau/nouveau_volt.c +@@ -27,7 +27,7 @@ + #include "nouveau_drv.h" + #include "nouveau_pm.h" + +-static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a }; ++static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; + static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); + + int +@@ -170,6 +170,13 @@ nouveau_volt_init(struct drm_device *dev) + */ + vidshift = 2; + break; ++ case 0x40: ++ headerlen = volt[1]; ++ recordlen = volt[2]; ++ entries = volt[3]; /* not a clue what the entries are for.. */ ++ vidmask = volt[11]; /* guess.. */ ++ vidshift = 0; ++ break; + default: + NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]); + return; +@@ -197,16 +204,37 @@ nouveau_volt_init(struct drm_device *dev) + } + + /* parse vbios entries into common format */ +- voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); +- if (!voltage->level) +- return; ++ voltage->version = volt[0]; ++ if (voltage->version < 0x40) { ++ voltage->nr_level = entries; ++ voltage->level = ++ kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); ++ if (!voltage->level) ++ return; + +- entry = volt + headerlen; +- for (i = 0; i < entries; i++, entry += recordlen) { +- voltage->level[i].voltage = entry[0]; +- voltage->level[i].vid = entry[1] >> vidshift; ++ entry = volt + headerlen; ++ for (i = 0; i < entries; i++, entry += recordlen) { ++ voltage->level[i].voltage = entry[0] * 10000; ++ voltage->level[i].vid = entry[1] >> vidshift; ++ } ++ } else { ++ u32 volt_uv = ROM32(volt[4]); ++ s16 step_uv = ROM16(volt[8]); ++ u8 vid; ++ ++ voltage->nr_level = voltage->vid_mask + 1; ++ voltage->level = kcalloc(voltage->nr_level, ++ sizeof(*voltage->level), GFP_KERNEL); ++ if (!voltage->level) ++ return; ++ ++ for (vid = 0; vid <= voltage->vid_mask; vid++) { ++ voltage->level[vid].voltage = volt_uv; ++ voltage->level[vid].vid = vid; ++ volt_uv += step_uv; ++ } + } +- voltage->nr_level = entries; ++ + voltage->supported = true; + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c +index 1715e14..6bd8518 100644 +--- a/drivers/gpu/drm/nouveau/nv04_display.c ++++ b/drivers/gpu/drm/nouveau/nv04_display.c +@@ -126,27 +126,6 @@ nv04_display_create(struct drm_device *dev) + + nouveau_hw_save_vga_fonts(dev, 1); + +- drm_mode_config_init(dev); +- drm_mode_create_scaling_mode_property(dev); +- drm_mode_create_dithering_property(dev); +- +- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; +- +- dev->mode_config.min_width = 0; +- dev->mode_config.min_height = 0; +- switch (dev_priv->card_type) { +- case NV_04: +- dev->mode_config.max_width = 2048; +- dev->mode_config.max_height = 2048; +- break; +- default: +- dev->mode_config.max_width = 4096; +- dev->mode_config.max_height = 4096; +- break; +- } +- +- dev->mode_config.fb_base = dev_priv->fb_phys; +- + nv04_crtc_create(dev, 0); + if (nv_two_heads(dev)) + nv04_crtc_create(dev, 1); +@@ -235,8 +214,6 @@ nv04_display_destroy(struct drm_device *dev) + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + crtc->funcs->restore(crtc); + +- drm_mode_config_cleanup(dev); +- + nouveau_hw_save_vga_fonts(dev, 0); + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c +index eb1c70d..9ae92a8 100644 +--- a/drivers/gpu/drm/nouveau/nv04_pm.c ++++ b/drivers/gpu/drm/nouveau/nv04_pm.c +@@ -68,6 +68,7 @@ void + nv04_pm_clock_set(struct drm_device *dev, void *pre_state) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + struct nv04_pm_state *state = pre_state; + u32 reg = state->pll.reg; + +@@ -85,6 +86,9 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) + nv_mask(dev, 0x1002c0, 0, 1 << 8); + } + ++ if (reg == NV_PRAMDAC_NVPLL_COEFF) ++ ptimer->init(dev); ++ + kfree(state); + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c +index 1d09ddd..263301b 100644 +--- a/drivers/gpu/drm/nouveau/nv04_timer.c ++++ b/drivers/gpu/drm/nouveau/nv04_timer.c +@@ -6,43 +6,75 @@ + int + nv04_timer_init(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 m, n, d; ++ + nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); + nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); + +- /* Just use the pre-existing values when possible for now; these regs +- * are not written in nv (driver writer missed a /4 on the address), and +- * writing 8 and 3 to the correct regs breaks the timings on the LVDS +- * hardware sequencing microcode. +- * A correct solution (involving calculations with the GPU PLL) can +- * be done when kernel modesetting lands +- */ +- if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || +- !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { +- nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008); +- nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003); ++ /* aim for 31.25MHz, which gives us nanosecond timestamps */ ++ d = 1000000 / 32; ++ ++ /* determine base clock for timer source */ ++ if (dev_priv->chipset < 0x40) { ++ n = dev_priv->engine.pm.clock_get(dev, PLL_CORE); ++ } else ++ if (dev_priv->chipset == 0x40) { ++ /*XXX: figure this out */ ++ n = 0; ++ } else { ++ n = dev_priv->crystal; ++ m = 1; ++ while (n < (d * 2)) { ++ n += (n / m); ++ m++; ++ } ++ ++ nv_wr32(dev, 0x009220, m - 1); ++ } ++ ++ if (!n) { ++ NV_WARN(dev, "PTIMER: unknown input clock freq\n"); ++ if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || ++ !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { ++ nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1); ++ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1); ++ } ++ return 0; ++ } ++ ++ /* reduce ratio to acceptable values */ ++ while (((n % 5) == 0) && ((d % 5) == 0)) { ++ n /= 5; ++ d /= 5; + } + ++ while (((n % 2) == 0) && ((d % 2) == 0)) { ++ n /= 2; ++ d /= 2; ++ } ++ ++ while (n > 0xffff || d > 0xffff) { ++ n >>= 1; ++ d >>= 1; ++ } ++ ++ nv_wr32(dev, NV04_PTIMER_NUMERATOR, n); ++ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d); + return 0; + } + +-uint64_t ++u64 + nv04_timer_read(struct drm_device *dev) + { +- uint32_t low; +- /* From kmmio dumps on nv28 this looks like how the blob does this. +- * It reads the high dword twice, before and after. +- * The only explanation seems to be that the 64-bit timer counter +- * advances between high and low dword reads and may corrupt the +- * result. Not confirmed. +- */ +- uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); +- uint32_t high1; ++ u32 hi, lo; ++ + do { +- high1 = high2; +- low = nv_rd32(dev, NV04_PTIMER_TIME_0); +- high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); +- } while (high1 != high2); +- return (((uint64_t)high2) << 32) | (uint64_t)low; ++ hi = nv_rd32(dev, NV04_PTIMER_TIME_1); ++ lo = nv_rd32(dev, NV04_PTIMER_TIME_0); ++ } while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1)); ++ ++ return ((u64)hi << 32 | lo); + } + + void +diff --git a/drivers/gpu/drm/nouveau/nv31_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c +new file mode 100644 +index 0000000..6f06a07 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c +@@ -0,0 +1,344 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_ramht.h" ++ ++struct nv31_mpeg_engine { ++ struct nouveau_exec_engine base; ++ atomic_t refcount; ++}; ++ ++ ++static int ++nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); ++ ++ if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) ++ return -EBUSY; ++ ++ chan->engctx[engine] = (void *)0xdeadcafe; ++ return 0; ++} ++ ++static void ++nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); ++ atomic_dec(&pmpeg->refcount); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx = NULL; ++ unsigned long flags; ++ int ret; ++ ++ NV_DEBUG(dev, "ch%d\n", chan->id); ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ctx, 0x78, 0x02001ec1); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); ++ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) ++ nv_wr32(dev, 0x00330c, ctx->pinst >> 4); ++ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static void ++nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ unsigned long flags; ++ u32 inst = 0x80000000 | (ctx->pinst >> 4); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ if (nv_rd32(dev, 0x00b318) == inst) ++ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ nouveau_gpuobj_ref(NULL, &ctx); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct drm_device *dev = chan->dev; ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; ++ ++ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 2; ++ obj->class = class; ++ ++ nv_wo32(obj, 0x00, class); ++ ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; ++} ++ ++static int ++nv31_mpeg_init(struct drm_device *dev, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ int i; ++ ++ /* VPE init */ ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000002); ++ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ ++ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) ++ pmpeg->base.set_tile_region(dev, i); ++ ++ /* PMPEG init */ ++ nv_wr32(dev, 0x00b32c, 0x00000000); ++ nv_wr32(dev, 0x00b314, 0x00000100); ++ nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); ++ nv_wr32(dev, 0x00b300, 0x02001ec1); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ ++ nv_wr32(dev, 0x00b100, 0xffffffff); ++ nv_wr32(dev, 0x00b140, 0xffffffff); ++ ++ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { ++ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int ++nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) ++{ ++ /*XXX: context save? */ ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x00b140, 0x00000000); ++ return 0; ++} ++ ++static int ++nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) ++{ ++ struct drm_device *dev = chan->dev; ++ u32 inst = data << 4; ++ u32 dma0 = nv_ri32(dev, inst + 0); ++ u32 dma1 = nv_ri32(dev, inst + 4); ++ u32 dma2 = nv_ri32(dev, inst + 8); ++ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); ++ u32 size = dma1 + 1; ++ ++ /* only allow linear DMA objects */ ++ if (!(dma0 & 0x00002000)) ++ return -EINVAL; ++ ++ if (mthd == 0x0190) { ++ /* DMA_CMD */ ++ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); ++ nv_wr32(dev, 0x00b334, base); ++ nv_wr32(dev, 0x00b324, size); ++ } else ++ if (mthd == 0x01a0) { ++ /* DMA_DATA */ ++ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); ++ nv_wr32(dev, 0x00b360, base); ++ nv_wr32(dev, 0x00b364, size); ++ } else { ++ /* DMA_IMAGE, VRAM only */ ++ if (dma0 & 0x000c0000) ++ return -EINVAL; ++ ++ nv_wr32(dev, 0x00b370, base); ++ nv_wr32(dev, 0x00b374, size); ++ } ++ ++ return 0; ++} ++ ++static int ++nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx; ++ unsigned long flags; ++ int i; ++ ++ /* hardcode drm channel id on nv3x, so swmthd lookup works */ ++ if (dev_priv->card_type < NV_40) ++ return 0; ++ ++ spin_lock_irqsave(&dev_priv->channels.lock, flags); ++ for (i = 0; i < dev_priv->engine.fifo.channels; i++) { ++ if (!dev_priv->channels.ptr[i]) ++ continue; ++ ++ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; ++ if (ctx && ctx->pinst == inst) ++ break; ++ } ++ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); ++ return i; ++} ++ ++static void ++nv31_vpe_set_tile_region(struct drm_device *dev, int i) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; ++ ++ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); ++ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); ++ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); ++} ++ ++static void ++nv31_mpeg_isr(struct drm_device *dev) ++{ ++ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; ++ u32 chid = nv31_mpeg_isr_chid(dev, inst); ++ u32 stat = nv_rd32(dev, 0x00b100); ++ u32 type = nv_rd32(dev, 0x00b230); ++ u32 mthd = nv_rd32(dev, 0x00b234); ++ u32 data = nv_rd32(dev, 0x00b238); ++ u32 show = stat; ++ ++ if (stat & 0x01000000) { ++ /* happens on initial binding of the object */ ++ if (type == 0x00000020 && mthd == 0x0000) { ++ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); ++ show &= ~0x01000000; ++ } ++ ++ if (type == 0x00000010) { ++ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) ++ show &= ~0x01000000; ++ } ++ } ++ ++ nv_wr32(dev, 0x00b100, stat); ++ nv_wr32(dev, 0x00b230, 0x00000001); ++ ++ if (show && nouveau_ratelimit()) { ++ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ chid, inst, stat, type, mthd, data); ++ } ++} ++ ++static void ++nv31_vpe_isr(struct drm_device *dev) ++{ ++ if (nv_rd32(dev, 0x00b100)) ++ nv31_mpeg_isr(dev); ++ ++ if (nv_rd32(dev, 0x00b800)) { ++ u32 stat = nv_rd32(dev, 0x00b800); ++ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); ++ nv_wr32(dev, 0xb800, stat); ++ } ++} ++ ++static void ++nv31_mpeg_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 0); ++ ++ NVOBJ_ENGINE_DEL(dev, MPEG); ++ kfree(pmpeg); ++} ++ ++int ++nv31_mpeg_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv31_mpeg_engine *pmpeg; ++ ++ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); ++ if (!pmpeg) ++ return -ENOMEM; ++ atomic_set(&pmpeg->refcount, 0); ++ ++ pmpeg->base.destroy = nv31_mpeg_destroy; ++ pmpeg->base.init = nv31_mpeg_init; ++ pmpeg->base.fini = nv31_mpeg_fini; ++ if (dev_priv->card_type < NV_40) { ++ pmpeg->base.context_new = nv31_mpeg_context_new; ++ pmpeg->base.context_del = nv31_mpeg_context_del; ++ } else { ++ pmpeg->base.context_new = nv40_mpeg_context_new; ++ pmpeg->base.context_del = nv40_mpeg_context_del; ++ } ++ pmpeg->base.object_new = nv31_mpeg_object_new; ++ ++ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between ++ * all VPE engines, for this driver's purposes the PMPEG engine ++ * will be treated as the "master" and handle the global VPE ++ * bits too ++ */ ++ pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; ++ nouveau_irq_register(dev, 0, nv31_vpe_isr); ++ ++ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); ++ NVOBJ_CLASS(dev, 0x3174, MPEG); ++ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); ++ ++#if 0 ++ NVOBJ_ENGINE_ADD(dev, ME, &pme->base); ++ NVOBJ_CLASS(dev, 0x4075, ME); ++#endif ++ return 0; ++ ++} +diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c +deleted file mode 100644 +index ad03a0e..0000000 +--- a/drivers/gpu/drm/nouveau/nv40_mpeg.c ++++ /dev/null +@@ -1,311 +0,0 @@ +-/* +- * Copyright 2011 Red Hat Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: Ben Skeggs +- */ +- +-#include "drmP.h" +-#include "nouveau_drv.h" +-#include "nouveau_ramht.h" +- +-struct nv40_mpeg_engine { +- struct nouveau_exec_engine base; +-}; +- +-static int +-nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) +-{ +- struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *ctx = NULL; +- unsigned long flags; +- int ret; +- +- NV_DEBUG(dev, "ch%d\n", chan->id); +- +- ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &ctx); +- if (ret) +- return ret; +- +- nv_wo32(ctx, 0x78, 0x02001ec1); +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000000); +- if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) +- nv_wr32(dev, 0x00330c, ctx->pinst >> 4); +- nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000001); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- +- chan->engctx[engine] = ctx; +- return 0; +-} +- +-static void +-nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) +-{ +- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; +- struct nouveau_gpuobj *ctx = chan->engctx[engine]; +- struct drm_device *dev = chan->dev; +- unsigned long flags; +- u32 inst = 0x80000000 | (ctx->pinst >> 4); +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); +- if (nv_rd32(dev, 0x00b318) == inst) +- nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- +- nouveau_gpuobj_ref(NULL, &ctx); +- chan->engctx[engine] = NULL; +-} +- +-static int +-nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, +- u32 handle, u16 class) +-{ +- struct drm_device *dev = chan->dev; +- struct nouveau_gpuobj *obj = NULL; +- int ret; +- +- ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &obj); +- if (ret) +- return ret; +- obj->engine = 2; +- obj->class = class; +- +- nv_wo32(obj, 0x00, class); +- +- ret = nouveau_ramht_insert(chan, handle, obj); +- nouveau_gpuobj_ref(NULL, &obj); +- return ret; +-} +- +-static int +-nv40_mpeg_init(struct drm_device *dev, int engine) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); +- int i; +- +- /* VPE init */ +- nv_mask(dev, 0x000200, 0x00000002, 0x00000000); +- nv_mask(dev, 0x000200, 0x00000002, 0x00000002); +- nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ +- nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ +- +- for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) +- pmpeg->base.set_tile_region(dev, i); +- +- /* PMPEG init */ +- nv_wr32(dev, 0x00b32c, 0x00000000); +- nv_wr32(dev, 0x00b314, 0x00000100); +- nv_wr32(dev, 0x00b220, 0x00000044); +- nv_wr32(dev, 0x00b300, 0x02001ec1); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); +- +- nv_wr32(dev, 0x00b100, 0xffffffff); +- nv_wr32(dev, 0x00b140, 0xffffffff); +- +- if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); +- return -EBUSY; +- } +- +- return 0; +-} +- +-static int +-nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend) +-{ +- /*XXX: context save? */ +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); +- nv_wr32(dev, 0x00b140, 0x00000000); +- return 0; +-} +- +-static int +-nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) +-{ +- struct drm_device *dev = chan->dev; +- u32 inst = data << 4; +- u32 dma0 = nv_ri32(dev, inst + 0); +- u32 dma1 = nv_ri32(dev, inst + 4); +- u32 dma2 = nv_ri32(dev, inst + 8); +- u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); +- u32 size = dma1 + 1; +- +- /* only allow linear DMA objects */ +- if (!(dma0 & 0x00002000)) +- return -EINVAL; +- +- if (mthd == 0x0190) { +- /* DMA_CMD */ +- nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); +- nv_wr32(dev, 0x00b334, base); +- nv_wr32(dev, 0x00b324, size); +- } else +- if (mthd == 0x01a0) { +- /* DMA_DATA */ +- nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); +- nv_wr32(dev, 0x00b360, base); +- nv_wr32(dev, 0x00b364, size); +- } else { +- /* DMA_IMAGE, VRAM only */ +- if (dma0 & 0x000c0000) +- return -EINVAL; +- +- nv_wr32(dev, 0x00b370, base); +- nv_wr32(dev, 0x00b374, size); +- } +- +- return 0; +-} +- +-static int +-nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *ctx; +- unsigned long flags; +- int i; +- +- spin_lock_irqsave(&dev_priv->channels.lock, flags); +- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- if (!dev_priv->channels.ptr[i]) +- continue; +- +- ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; +- if (ctx && ctx->pinst == inst) +- break; +- } +- spin_unlock_irqrestore(&dev_priv->channels.lock, flags); +- return i; +-} +- +-static void +-nv40_vpe_set_tile_region(struct drm_device *dev, int i) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; +- +- nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); +- nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); +- nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); +-} +- +-static void +-nv40_mpeg_isr(struct drm_device *dev) +-{ +- u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; +- u32 chid = nv40_mpeg_isr_chid(dev, inst); +- u32 stat = nv_rd32(dev, 0x00b100); +- u32 type = nv_rd32(dev, 0x00b230); +- u32 mthd = nv_rd32(dev, 0x00b234); +- u32 data = nv_rd32(dev, 0x00b238); +- u32 show = stat; +- +- if (stat & 0x01000000) { +- /* happens on initial binding of the object */ +- if (type == 0x00000020 && mthd == 0x0000) { +- nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); +- show &= ~0x01000000; +- } +- +- if (type == 0x00000010) { +- if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) +- show &= ~0x01000000; +- } +- } +- +- nv_wr32(dev, 0x00b100, stat); +- nv_wr32(dev, 0x00b230, 0x00000001); +- +- if (show && nouveau_ratelimit()) { +- NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", +- chid, inst, stat, type, mthd, data); +- } +-} +- +-static void +-nv40_vpe_isr(struct drm_device *dev) +-{ +- if (nv_rd32(dev, 0x00b100)) +- nv40_mpeg_isr(dev); +- +- if (nv_rd32(dev, 0x00b800)) { +- u32 stat = nv_rd32(dev, 0x00b800); +- NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); +- nv_wr32(dev, 0xb800, stat); +- } +-} +- +-static void +-nv40_mpeg_destroy(struct drm_device *dev, int engine) +-{ +- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); +- +- nouveau_irq_unregister(dev, 0); +- +- NVOBJ_ENGINE_DEL(dev, MPEG); +- kfree(pmpeg); +-} +- +-int +-nv40_mpeg_create(struct drm_device *dev) +-{ +- struct nv40_mpeg_engine *pmpeg; +- +- pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); +- if (!pmpeg) +- return -ENOMEM; +- +- pmpeg->base.destroy = nv40_mpeg_destroy; +- pmpeg->base.init = nv40_mpeg_init; +- pmpeg->base.fini = nv40_mpeg_fini; +- pmpeg->base.context_new = nv40_mpeg_context_new; +- pmpeg->base.context_del = nv40_mpeg_context_del; +- pmpeg->base.object_new = nv40_mpeg_object_new; +- +- /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between +- * all VPE engines, for this driver's purposes the PMPEG engine +- * will be treated as the "master" and handle the global VPE +- * bits too +- */ +- pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; +- nouveau_irq_register(dev, 0, nv40_vpe_isr); +- +- NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); +- NVOBJ_CLASS(dev, 0x3174, MPEG); +- NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); +- NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); +- NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); +- +-#if 0 +- NVOBJ_ENGINE_ADD(dev, ME, &pme->base); +- NVOBJ_CLASS(dev, 0x4075, ME); +-#endif +- return 0; +- +-} +diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c +new file mode 100644 +index 0000000..e676b0d +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nv40_pm.c +@@ -0,0 +1,348 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_bios.h" ++#include "nouveau_pm.h" ++#include "nouveau_hw.h" ++ ++#define min2(a,b) ((a) < (b) ? (a) : (b)) ++ ++static u32 ++read_pll_1(struct drm_device *dev, u32 reg) ++{ ++ u32 ctrl = nv_rd32(dev, reg + 0x00); ++ int P = (ctrl & 0x00070000) >> 16; ++ int N = (ctrl & 0x0000ff00) >> 8; ++ int M = (ctrl & 0x000000ff) >> 0; ++ u32 ref = 27000, clk = 0; ++ ++ if (ctrl & 0x80000000) ++ clk = ref * N / M; ++ ++ return clk >> P; ++} ++ ++static u32 ++read_pll_2(struct drm_device *dev, u32 reg) ++{ ++ u32 ctrl = nv_rd32(dev, reg + 0x00); ++ u32 coef = nv_rd32(dev, reg + 0x04); ++ int N2 = (coef & 0xff000000) >> 24; ++ int M2 = (coef & 0x00ff0000) >> 16; ++ int N1 = (coef & 0x0000ff00) >> 8; ++ int M1 = (coef & 0x000000ff) >> 0; ++ int P = (ctrl & 0x00070000) >> 16; ++ u32 ref = 27000, clk = 0; ++ ++ if ((ctrl & 0x80000000) && M1) { ++ clk = ref * N1 / M1; ++ if ((ctrl & 0x40000100) == 0x40000000) { ++ if (M2) ++ clk = clk * N2 / M2; ++ else ++ clk = 0; ++ } ++ } ++ ++ return clk >> P; ++} ++ ++static u32 ++read_clk(struct drm_device *dev, u32 src) ++{ ++ switch (src) { ++ case 3: ++ return read_pll_2(dev, 0x004000); ++ case 2: ++ return read_pll_1(dev, 0x004008); ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++int ++nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ u32 ctrl = nv_rd32(dev, 0x00c040); ++ ++ perflvl->core = read_clk(dev, (ctrl & 0x00000003) >> 0); ++ perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4); ++ perflvl->memory = read_pll_2(dev, 0x4020); ++ return 0; ++} ++ ++struct nv40_pm_state { ++ u32 ctrl; ++ u32 npll_ctrl; ++ u32 npll_coef; ++ u32 spll; ++ u32 mpll_ctrl; ++ u32 mpll_coef; ++}; ++ ++static int ++nv40_calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll, ++ u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P) ++{ ++ struct nouveau_pll_vals coef; ++ int ret; ++ ++ ret = get_pll_limits(dev, reg, pll); ++ if (ret) ++ return ret; ++ ++ if (clk < pll->vco1.maxfreq) ++ pll->vco2.maxfreq = 0; ++ ++ ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef); ++ if (ret == 0) ++ return -ERANGE; ++ ++ *N1 = coef.N1; ++ *M1 = coef.M1; ++ if (N2 && M2) { ++ if (pll->vco2.maxfreq) { ++ *N2 = coef.N2; ++ *M2 = coef.M2; ++ } else { ++ *N2 = 1; ++ *M2 = 1; ++ } ++ } ++ *log2P = coef.log2P; ++ return 0; ++} ++ ++void * ++nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ struct nv40_pm_state *info; ++ struct pll_lims pll; ++ int N1, N2, M1, M2, log2P; ++ int ret; ++ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return ERR_PTR(-ENOMEM); ++ ++ /* core/geometric clock */ ++ ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core, ++ &N1, &M1, &N2, &M2, &log2P); ++ if (ret < 0) ++ goto out; ++ ++ if (N2 == M2) { ++ info->npll_ctrl = 0x80000100 | (log2P << 16); ++ info->npll_coef = (N1 << 8) | M1; ++ } else { ++ info->npll_ctrl = 0xc0000000 | (log2P << 16); ++ info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; ++ } ++ ++ /* use the second PLL for shader/rop clock, if it differs from core */ ++ if (perflvl->shader && perflvl->shader != perflvl->core) { ++ ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader, ++ &N1, &M1, NULL, NULL, &log2P); ++ if (ret < 0) ++ goto out; ++ ++ info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; ++ info->ctrl = 0x00000223; ++ } else { ++ info->spll = 0x00000000; ++ info->ctrl = 0x00000333; ++ } ++ ++ /* memory clock */ ++ if (!perflvl->memory) { ++ info->mpll_ctrl = 0x00000000; ++ goto out; ++ } ++ ++ ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory, ++ &N1, &M1, &N2, &M2, &log2P); ++ if (ret < 0) ++ goto out; ++ ++ info->mpll_ctrl = 0x80000000 | (log2P << 16); ++ info->mpll_ctrl |= min2(pll.log2p_bias + log2P, pll.max_log2p) << 20; ++ if (N2 == M2) { ++ info->mpll_ctrl |= 0x00000100; ++ info->mpll_coef = (N1 << 8) | M1; ++ } else { ++ info->mpll_ctrl |= 0x40000000; ++ info->mpll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; ++ } ++ ++out: ++ if (ret < 0) { ++ kfree(info); ++ info = ERR_PTR(ret); ++ } ++ return info; ++} ++ ++static bool ++nv40_pm_gr_idle(void *data) ++{ ++ struct drm_device *dev = data; ++ ++ if ((nv_rd32(dev, 0x400760) & 0x000000f0) >> 4 != ++ (nv_rd32(dev, 0x400760) & 0x0000000f)) ++ return false; ++ ++ if (nv_rd32(dev, 0x400700)) ++ return false; ++ ++ return true; ++} ++ ++void ++nv40_pm_clocks_set(struct drm_device *dev, void *pre_state) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv40_pm_state *info = pre_state; ++ unsigned long flags; ++ struct bit_entry M; ++ u32 crtc_mask = 0; ++ u8 sr1[2]; ++ int i; ++ ++ /* determine which CRTCs are active, fetch VGA_SR1 for each */ ++ for (i = 0; i < 2; i++) { ++ u32 vbl = nv_rd32(dev, 0x600808 + (i * 0x2000)); ++ u32 cnt = 0; ++ do { ++ if (vbl != nv_rd32(dev, 0x600808 + (i * 0x2000))) { ++ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); ++ sr1[i] = nv_rd08(dev, 0x0c03c5 + (i * 0x2000)); ++ if (!(sr1[i] & 0x20)) ++ crtc_mask |= (1 << i); ++ break; ++ } ++ udelay(1); ++ } while (cnt++ < 32); ++ } ++ ++ /* halt and idle engines */ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, 0x002500, 0x00000010, 0x00000000)) ++ goto resume; ++ nv_mask(dev, 0x003220, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000)) ++ goto resume; ++ nv_mask(dev, 0x003200, 0x00000001, 0x00000000); ++ nv04_fifo_cache_pull(dev, false); ++ ++ if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev)) ++ goto resume; ++ ++ /* set engine clocks */ ++ nv_mask(dev, 0x00c040, 0x00000333, 0x00000000); ++ nv_wr32(dev, 0x004004, info->npll_coef); ++ nv_mask(dev, 0x004000, 0xc0070100, info->npll_ctrl); ++ nv_mask(dev, 0x004008, 0xc007ffff, info->spll); ++ mdelay(5); ++ nv_mask(dev, 0x00c040, 0x00000333, info->ctrl); ++ ++ if (!info->mpll_ctrl) ++ goto resume; ++ ++ /* wait for vblank start on active crtcs, disable memory access */ ++ for (i = 0; i < 2; i++) { ++ if (!(crtc_mask & (1 << i))) ++ continue; ++ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); ++ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); ++ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); ++ nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); ++ } ++ ++ /* prepare ram for reclocking */ ++ nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */ ++ nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ ++ nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ ++ nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ ++ nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */ ++ ++ /* change the PLL of each memory partition */ ++ nv_mask(dev, 0x00c040, 0x0000c000, 0x00000000); ++ switch (dev_priv->chipset) { ++ case 0x40: ++ case 0x45: ++ case 0x41: ++ case 0x42: ++ case 0x47: ++ nv_mask(dev, 0x004044, 0xc0771100, info->mpll_ctrl); ++ nv_mask(dev, 0x00402c, 0xc0771100, info->mpll_ctrl); ++ nv_wr32(dev, 0x004048, info->mpll_coef); ++ nv_wr32(dev, 0x004030, info->mpll_coef); ++ case 0x43: ++ case 0x49: ++ case 0x4b: ++ nv_mask(dev, 0x004038, 0xc0771100, info->mpll_ctrl); ++ nv_wr32(dev, 0x00403c, info->mpll_coef); ++ default: ++ nv_mask(dev, 0x004020, 0xc0771100, info->mpll_ctrl); ++ nv_wr32(dev, 0x004024, info->mpll_coef); ++ break; ++ } ++ udelay(100); ++ nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000); ++ ++ /* re-enable normal operation of memory controller */ ++ nv_wr32(dev, 0x1002dc, 0x00000000); ++ nv_mask(dev, 0x100210, 0x80000000, 0x80000000); ++ udelay(100); ++ ++ /* execute memory reset script from vbios */ ++ if (!bit_table(dev, 'M', &M)) ++ nouveau_bios_init_exec(dev, ROM16(M.data[0])); ++ ++ /* make sure we're in vblank (hopefully the same one as before), and ++ * then re-enable crtc memory access ++ */ ++ for (i = 0; i < 2; i++) { ++ if (!(crtc_mask & (1 << i))) ++ continue; ++ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); ++ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); ++ nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i]); ++ } ++ ++ /* resume engines */ ++resume: ++ nv_wr32(dev, 0x003250, 0x00000001); ++ nv_mask(dev, 0x003220, 0x00000001, 0x00000001); ++ nv_wr32(dev, 0x003200, 0x00000001); ++ nv_wr32(dev, 0x002500, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ kfree(info); ++} +diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c +index 5d98907..882080e 100644 +--- a/drivers/gpu/drm/nouveau/nv50_crtc.c ++++ b/drivers/gpu/drm/nouveau/nv50_crtc.c +@@ -329,8 +329,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) + + drm_crtc_cleanup(&nv_crtc->base); + +- nv50_cursor_fini(nv_crtc); +- + nouveau_bo_unmap(nv_crtc->lut.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); + nouveau_bo_unmap(nv_crtc->cursor.nvbo); +diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c +index 9752c35..adfc9b6 100644 +--- a/drivers/gpu/drm/nouveau/nv50_cursor.c ++++ b/drivers/gpu/drm/nouveau/nv50_cursor.c +@@ -137,21 +137,3 @@ nv50_cursor_init(struct nouveau_crtc *nv_crtc) + nv_crtc->cursor.show = nv50_cursor_show; + return 0; + } +- +-void +-nv50_cursor_fini(struct nouveau_crtc *nv_crtc) +-{ +- struct drm_device *dev = nv_crtc->base.dev; +- int idx = nv_crtc->index; +- +- NV_DEBUG_KMS(dev, "\n"); +- +- nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0); +- if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), +- NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { +- NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); +- NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", +- nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx))); +- } +-} +- +diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c +index db1a5f4..d23ca00 100644 +--- a/drivers/gpu/drm/nouveau/nv50_display.c ++++ b/drivers/gpu/drm/nouveau/nv50_display.c +@@ -247,6 +247,16 @@ static int nv50_display_disable(struct drm_device *dev) + } + } + ++ for (i = 0; i < 2; i++) { ++ nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0); ++ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), ++ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { ++ NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); ++ NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", ++ nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); ++ } ++ } ++ + nv50_evo_fini(dev); + + for (i = 0; i < 3; i++) { +@@ -286,23 +296,6 @@ int nv50_display_create(struct drm_device *dev) + return -ENOMEM; + dev_priv->engine.display.priv = priv; + +- /* init basic kernel modesetting */ +- drm_mode_config_init(dev); +- +- /* Initialise some optional connector properties. */ +- drm_mode_create_scaling_mode_property(dev); +- drm_mode_create_dithering_property(dev); +- +- dev->mode_config.min_width = 0; +- dev->mode_config.min_height = 0; +- +- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; +- +- dev->mode_config.max_width = 8192; +- dev->mode_config.max_height = 8192; +- +- dev->mode_config.fb_base = dev_priv->fb_phys; +- + /* Create CRTC objects */ + for (i = 0; i < 2; i++) + nv50_crtc_create(dev, i); +@@ -364,8 +357,6 @@ nv50_display_destroy(struct drm_device *dev) + + NV_DEBUG_KMS(dev, "\n"); + +- drm_mode_config_cleanup(dev); +- + nv50_display_disable(dev); + nouveau_irq_unregister(dev, 26); + kfree(disp); +@@ -698,7 +689,7 @@ nv50_display_unk10_handler(struct drm_device *dev) + struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; + + if (dcb->type == type && (dcb->or & (1 << or))) { +- nouveau_bios_run_display_table(dev, dcb, 0, -1); ++ nouveau_bios_run_display_table(dev, 0, -1, dcb, -1); + disp->irq.dcb = dcb; + goto ack; + } +@@ -711,37 +702,6 @@ ack: + } + + static void +-nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) +-{ +- int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1); +- struct drm_encoder *encoder; +- uint32_t tmp, unk0 = 0, unk1 = 0; +- +- if (dcb->type != OUTPUT_DP) +- return; +- +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- +- if (nv_encoder->dcb == dcb) { +- unk0 = nv_encoder->dp.unk0; +- unk1 = nv_encoder->dp.unk1; +- break; +- } +- } +- +- if (unk0 || unk1) { +- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); +- tmp &= 0xfffffe03; +- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0); +- +- tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link)); +- tmp &= 0xfef080c0; +- nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1); +- } +-} +- +-static void + nv50_display_unk20_handler(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -753,7 +713,7 @@ nv50_display_unk20_handler(struct drm_device *dev) + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); + dcb = disp->irq.dcb; + if (dcb) { +- nouveau_bios_run_display_table(dev, dcb, 0, -2); ++ nouveau_bios_run_display_table(dev, 0, -2, dcb, -1); + disp->irq.dcb = NULL; + } + +@@ -837,9 +797,15 @@ nv50_display_unk20_handler(struct drm_device *dev) + } + + script = nv50_display_script_select(dev, dcb, mc, pclk); +- nouveau_bios_run_display_table(dev, dcb, script, pclk); ++ nouveau_bios_run_display_table(dev, script, pclk, dcb, -1); + +- nv50_display_unk20_dp_hack(dev, dcb); ++ if (type == OUTPUT_DP) { ++ int link = !(dcb->dpconf.sor.link & 1); ++ if ((mc & 0x000f0000) == 0x00020000) ++ nouveau_dp_tu_update(dev, or, link, pclk, 18); ++ else ++ nouveau_dp_tu_update(dev, or, link, pclk, 24); ++ } + + if (dcb->type != OUTPUT_ANALOG) { + tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); +@@ -904,7 +870,7 @@ nv50_display_unk40_handler(struct drm_device *dev) + if (!dcb) + goto ack; + +- nouveau_bios_run_display_table(dev, dcb, script, -pclk); ++ nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1); + nv50_display_unk40_dp_set_tmds(dev, dcb); + + ack: +diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c +index d4f4206..793a5cc 100644 +--- a/drivers/gpu/drm/nouveau/nv50_gpio.c ++++ b/drivers/gpu/drm/nouveau/nv50_gpio.c +@@ -98,6 +98,37 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) + } + + int ++nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) ++{ ++ struct dcb_gpio_entry *gpio; ++ u32 v; ++ ++ gpio = nouveau_bios_gpio_entry(dev, tag); ++ if (!gpio) ++ return -ENOENT; ++ ++ v = nv_rd32(dev, 0x00d610 + (gpio->line * 4)); ++ v &= 0x00004000; ++ return (!!v == (gpio->state[1] & 1)); ++} ++ ++int ++nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) ++{ ++ struct dcb_gpio_entry *gpio; ++ u32 v; ++ ++ gpio = nouveau_bios_gpio_entry(dev, tag); ++ if (!gpio) ++ return -ENOENT; ++ ++ v = gpio->state[state] ^ 2; ++ ++ nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12); ++ return 0; ++} ++ ++int + nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, + void (*handler)(void *, int), void *data) + { +diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c +index d43c46c..8c979b3 100644 +--- a/drivers/gpu/drm/nouveau/nv50_graph.c ++++ b/drivers/gpu/drm/nouveau/nv50_graph.c +@@ -120,70 +120,62 @@ nv50_graph_unload_context(struct drm_device *dev) + return 0; + } + +-static void +-nv50_graph_init_reset(struct drm_device *dev) +-{ +- uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21); +- NV_DEBUG(dev, "\n"); +- +- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e); +- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | pmc_e); +-} +- +-static void +-nv50_graph_init_intr(struct drm_device *dev) +-{ +- NV_DEBUG(dev, "\n"); +- +- nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); +- nv_wr32(dev, 0x400138, 0xffffffff); +- nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); +-} +- +-static void +-nv50_graph_init_regs__nv(struct drm_device *dev) ++static int ++nv50_graph_init(struct drm_device *dev, int engine) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t units = nv_rd32(dev, 0x1540); ++ struct nv50_graph_engine *pgraph = nv_engine(dev, engine); ++ u32 units = nv_rd32(dev, 0x001540); + int i; + + NV_DEBUG(dev, "\n"); + ++ /* master reset */ ++ nv_mask(dev, 0x000200, 0x00200100, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00200100, 0x00200100); ++ nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ ++ ++ /* reset/enable traps and interrupts */ + nv_wr32(dev, 0x400804, 0xc0000000); + nv_wr32(dev, 0x406800, 0xc0000000); + nv_wr32(dev, 0x400c04, 0xc0000000); + nv_wr32(dev, 0x401800, 0xc0000000); + nv_wr32(dev, 0x405018, 0xc0000000); + nv_wr32(dev, 0x402000, 0xc0000000); +- + for (i = 0; i < 16; i++) { +- if (units & 1 << i) { +- if (dev_priv->chipset < 0xa0) { +- nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); +- nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); +- nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); +- } else { +- nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); +- nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); +- nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); +- } ++ if (!(units & (1 << i))) ++ continue; ++ ++ if (dev_priv->chipset < 0xa0) { ++ nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); ++ nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); ++ nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); ++ } else { ++ nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); ++ nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); ++ nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); + } + } + + nv_wr32(dev, 0x400108, 0xffffffff); +- +- nv_wr32(dev, 0x400824, 0x00004000); ++ nv_wr32(dev, 0x400138, 0xffffffff); ++ nv_wr32(dev, 0x400100, 0xffffffff); ++ nv_wr32(dev, 0x40013c, 0xffffffff); + nv_wr32(dev, 0x400500, 0x00010001); +-} +- +-static void +-nv50_graph_init_zcull(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int i; + +- NV_DEBUG(dev, "\n"); ++ /* upload context program, initialise ctxctl defaults */ ++ nv_wr32(dev, 0x400324, 0x00000000); ++ for (i = 0; i < pgraph->ctxprog_size; i++) ++ nv_wr32(dev, 0x400328, pgraph->ctxprog[i]); ++ nv_wr32(dev, 0x400824, 0x00000000); ++ nv_wr32(dev, 0x400828, 0x00000000); ++ nv_wr32(dev, 0x40082c, 0x00000000); ++ nv_wr32(dev, 0x400830, 0x00000000); ++ nv_wr32(dev, 0x400724, 0x00000000); ++ nv_wr32(dev, 0x40032c, 0x00000000); ++ nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ + ++ /* some unknown zcull magic */ + switch (dev_priv->chipset & 0xf0) { + case 0x50: + case 0x80: +@@ -212,43 +204,7 @@ nv50_graph_init_zcull(struct drm_device *dev) + nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000); + nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000); + } +-} +- +-static int +-nv50_graph_init_ctxctl(struct drm_device *dev) +-{ +- struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR); +- int i; +- +- NV_DEBUG(dev, "\n"); +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); +- for (i = 0; i < pgraph->ctxprog_size; i++) +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]); +- +- nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ +- nv_wr32(dev, 0x400320, 4); +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); +- return 0; +-} +- +-static int +-nv50_graph_init(struct drm_device *dev, int engine) +-{ +- int ret; +- +- NV_DEBUG(dev, "\n"); +- +- nv50_graph_init_reset(dev); +- nv50_graph_init_regs__nv(dev); +- nv50_graph_init_zcull(dev); +- +- ret = nv50_graph_init_ctxctl(dev); +- if (ret) +- return ret; + +- nv50_graph_init_intr(dev); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c +index de9abff..d05c2c3 100644 +--- a/drivers/gpu/drm/nouveau/nv50_grctx.c ++++ b/drivers/gpu/drm/nouveau/nv50_grctx.c +@@ -40,6 +40,12 @@ + #define CP_FLAG_UNK0B ((0 * 32) + 0xb) + #define CP_FLAG_UNK0B_CLEAR 0 + #define CP_FLAG_UNK0B_SET 1 ++#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe) ++#define CP_FLAG_XFER_SWITCH_DISABLE 0 ++#define CP_FLAG_XFER_SWITCH_ENABLE 1 ++#define CP_FLAG_STATE ((0 * 32) + 0x1c) ++#define CP_FLAG_STATE_STOPPED 0 ++#define CP_FLAG_STATE_RUNNING 1 + #define CP_FLAG_UNK1D ((0 * 32) + 0x1d) + #define CP_FLAG_UNK1D_CLEAR 0 + #define CP_FLAG_UNK1D_SET 1 +@@ -194,6 +200,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx) + "the devs.\n"); + return -ENOSYS; + } ++ ++ cp_set (ctx, STATE, RUNNING); ++ cp_set (ctx, XFER_SWITCH, ENABLE); + /* decide whether we're loading/unloading the context */ + cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); + cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); +@@ -260,6 +269,8 @@ nv50_grctx_init(struct nouveau_grctx *ctx) + cp_name(ctx, cp_exit); + cp_set (ctx, USER_SAVE, NOT_PENDING); + cp_set (ctx, USER_LOAD, NOT_PENDING); ++ cp_set (ctx, XFER_SWITCH, DISABLE); ++ cp_set (ctx, STATE, STOPPED); + cp_out (ctx, CP_END); + ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */ + +diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c +index 8a28100..3d5a86b 100644 +--- a/drivers/gpu/drm/nouveau/nv50_pm.c ++++ b/drivers/gpu/drm/nouveau/nv50_pm.c +@@ -115,15 +115,15 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state) + BIT_M.version == 1 && BIT_M.length >= 0x0b) { + script = ROM16(BIT_M.data[0x05]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + script = ROM16(BIT_M.data[0x07]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + script = ROM16(BIT_M.data[0x09]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + +- nouveau_bios_run_init_table(dev, perflvl->memscript, NULL); ++ nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1); + } + + if (state->type == PLL_MEMORY) { +diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c +index ffe8b48..2633aa8 100644 +--- a/drivers/gpu/drm/nouveau/nv50_sor.c ++++ b/drivers/gpu/drm/nouveau/nv50_sor.c +@@ -124,7 +124,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) + if (mode == DRM_MODE_DPMS_ON) { + u8 status = DP_SET_POWER_D0; + nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); +- nouveau_dp_link_train(encoder); ++ nouveau_dp_link_train(encoder, nv_encoder->dp.datarate); + } else { + u8 status = DP_SET_POWER_D3; + nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); +@@ -187,14 +187,13 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); ++ struct nouveau_connector *nv_connector; + uint32_t mode_ctl = 0; + int ret; + + NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n", + nv_encoder->or, nv_encoder->dcb->type, crtc->index); + +- nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); +- + switch (nv_encoder->dcb->type) { + case OUTPUT_TMDS: + if (nv_encoder->dcb->sorconf.link & 1) { +@@ -206,7 +205,15 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + mode_ctl = 0x0200; + break; + case OUTPUT_DP: +- mode_ctl |= (nv_encoder->dp.mc_unknown << 16); ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (nv_connector && nv_connector->base.display_info.bpc == 6) { ++ nv_encoder->dp.datarate = crtc->mode->clock * 18 / 8; ++ mode_ctl |= 0x00020000; ++ } else { ++ nv_encoder->dp.datarate = crtc->mode->clock * 24 / 8; ++ mode_ctl |= 0x00050000; ++ } ++ + if (nv_encoder->dcb->sorconf.link & 1) + mode_ctl |= 0x00000800; + else +@@ -227,6 +234,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NVSYNC; + ++ nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); ++ + ret = RING_SPACE(evo, 2); + if (ret) { + NV_ERROR(dev, "no space while connecting SOR\n"); +@@ -313,31 +322,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; + +- if (nv_encoder->dcb->type == OUTPUT_DP) { +- int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1); +- uint32_t tmp; +- +- tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); +- if (!tmp) +- tmp = nv_rd32(dev, 0x610798 + (or * 8)); +- +- switch ((tmp & 0x00000f00) >> 8) { +- case 8: +- case 9: +- nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16; +- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); +- nv_encoder->dp.unk0 = tmp & 0x000001fc; +- tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link)); +- nv_encoder->dp.unk1 = tmp & 0x010f7f3f; +- break; +- default: +- break; +- } +- +- if (!nv_encoder->dp.mc_unknown) +- nv_encoder->dp.mc_unknown = 5; +- } +- + drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c +index af32dae..9da2383 100644 +--- a/drivers/gpu/drm/nouveau/nv50_vram.c ++++ b/drivers/gpu/drm/nouveau/nv50_vram.c +@@ -51,7 +51,7 @@ void + nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_mm *mm = dev_priv->engine.vram.mm; ++ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *this; + struct nouveau_mem *mem; + +@@ -82,7 +82,7 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, + u32 memtype, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_mm *mm = dev_priv->engine.vram.mm; ++ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int comp = (memtype & 0x300) >> 8; +diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c +index e4b2b9e..618c144 100644 +--- a/drivers/gpu/drm/nouveau/nva3_pm.c ++++ b/drivers/gpu/drm/nouveau/nva3_pm.c +@@ -27,178 +27,316 @@ + #include "nouveau_bios.h" + #include "nouveau_pm.h" + +-/* This is actually a lot more complex than it appears here, but hopefully +- * this should be able to deal with what the VBIOS leaves for us.. +- * +- * If not, well, I'll jump off that bridge when I come to it. +- */ ++static u32 read_clk(struct drm_device *, int, bool); ++static u32 read_pll(struct drm_device *, int, u32); + +-struct nva3_pm_state { +- enum pll_types type; +- u32 src0; +- u32 src1; +- u32 ctrl; +- u32 coef; +- u32 old_pnm; +- u32 new_pnm; +- u32 new_div; +-}; ++static u32 ++read_vco(struct drm_device *dev, int clk) ++{ ++ u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4)); ++ if ((sctl & 0x00000030) != 0x00000030) ++ return read_pll(dev, 0x41, 0x00e820); ++ return read_pll(dev, 0x42, 0x00e8a0); ++} + +-static int +-nva3_pm_pll_offset(u32 id) ++static u32 ++read_clk(struct drm_device *dev, int clk, bool ignore_en) + { +- static const u32 pll_map[] = { +- 0x00, PLL_CORE, +- 0x01, PLL_SHADER, +- 0x02, PLL_MEMORY, +- 0x00, 0x00 +- }; +- const u32 *map = pll_map; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 sctl, sdiv, sclk; + +- while (map[1]) { +- if (id == map[1]) +- return map[0]; +- map += 2; ++ /* refclk for the 0xe8xx plls is a fixed frequency */ ++ if (clk >= 0x40) { ++ if (dev_priv->chipset == 0xaf) { ++ /* no joke.. seriously.. sigh.. */ ++ return nv_rd32(dev, 0x00471c) * 1000; ++ } ++ ++ return dev_priv->crystal; + } + +- return -ENOENT; ++ sctl = nv_rd32(dev, 0x4120 + (clk * 4)); ++ if (!ignore_en && !(sctl & 0x00000100)) ++ return 0; ++ ++ switch (sctl & 0x00003000) { ++ case 0x00000000: ++ return dev_priv->crystal; ++ case 0x00002000: ++ if (sctl & 0x00000040) ++ return 108000; ++ return 100000; ++ case 0x00003000: ++ sclk = read_vco(dev, clk); ++ sdiv = ((sctl & 0x003f0000) >> 16) + 2; ++ return (sclk * 2) / sdiv; ++ default: ++ return 0; ++ } + } + +-int +-nva3_pm_clock_get(struct drm_device *dev, u32 id) ++static u32 ++read_pll(struct drm_device *dev, int clk, u32 pll) ++{ ++ u32 ctrl = nv_rd32(dev, pll + 0); ++ u32 sclk = 0, P = 1, N = 1, M = 1; ++ ++ if (!(ctrl & 0x00000008)) { ++ if (ctrl & 0x00000001) { ++ u32 coef = nv_rd32(dev, pll + 4); ++ M = (coef & 0x000000ff) >> 0; ++ N = (coef & 0x0000ff00) >> 8; ++ P = (coef & 0x003f0000) >> 16; ++ ++ /* no post-divider on these.. */ ++ if ((pll & 0x00ff00) == 0x00e800) ++ P = 1; ++ ++ sclk = read_clk(dev, 0x00 + clk, false); ++ } ++ } else { ++ sclk = read_clk(dev, 0x10 + clk, false); ++ } ++ ++ return sclk * N / (M * P); ++} ++ ++struct creg { ++ u32 clk; ++ u32 pll; ++}; ++ ++static int ++calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg) + { +- u32 src0, src1, ctrl, coef; +- struct pll_lims pll; +- int ret, off; +- int P, N, M; ++ struct pll_lims limits; ++ u32 oclk, sclk, sdiv; ++ int P, N, M, diff; ++ int ret; ++ ++ reg->pll = 0; ++ reg->clk = 0; ++ if (!khz) { ++ NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk); ++ return 0; ++ } ++ ++ switch (khz) { ++ case 27000: ++ reg->clk = 0x00000100; ++ return khz; ++ case 100000: ++ reg->clk = 0x00002100; ++ return khz; ++ case 108000: ++ reg->clk = 0x00002140; ++ return khz; ++ default: ++ sclk = read_vco(dev, clk); ++ sdiv = min((sclk * 2) / (khz - 2999), (u32)65); ++ /* if the clock has a PLL attached, and we can get a within ++ * [-2, 3) MHz of a divider, we'll disable the PLL and use ++ * the divider instead. ++ * ++ * divider can go as low as 2, limited here because NVIDIA ++ * and the VBIOS on my NVA8 seem to prefer using the PLL ++ * for 810MHz - is there a good reason? ++ */ ++ if (sdiv > 4) { ++ oclk = (sclk * 2) / sdiv; ++ diff = khz - oclk; ++ if (!pll || (diff >= -2000 && diff < 3000)) { ++ reg->clk = (((sdiv - 2) << 16) | 0x00003100); ++ return oclk; ++ } ++ } + +- ret = get_pll_limits(dev, id, &pll); ++ if (!pll) { ++ NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk); ++ return -ERANGE; ++ } ++ ++ break; ++ } ++ ++ ret = get_pll_limits(dev, pll, &limits); + if (ret) + return ret; + +- off = nva3_pm_pll_offset(id); +- if (off < 0) +- return off; ++ limits.refclk = read_clk(dev, clk - 0x10, true); ++ if (!limits.refclk) ++ return -EINVAL; ++ ++ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); ++ if (ret >= 0) { ++ reg->clk = nv_rd32(dev, 0x4120 + (clk * 4)); ++ reg->pll = (P << 16) | (N << 8) | M; ++ } ++ return ret; ++} ++ ++static void ++prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg) ++{ ++ const u32 src0 = 0x004120 + (clk * 4); ++ const u32 src1 = 0x004160 + (clk * 4); ++ const u32 ctrl = pll + 0; ++ const u32 coef = pll + 4; ++ u32 cntl; ++ ++ if (!reg->clk && !reg->pll) { ++ NV_DEBUG(dev, "no clock for %02x\n", clk); ++ return; ++ } + +- src0 = nv_rd32(dev, 0x4120 + (off * 4)); +- src1 = nv_rd32(dev, 0x4160 + (off * 4)); +- ctrl = nv_rd32(dev, pll.reg + 0); +- coef = nv_rd32(dev, pll.reg + 4); +- NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", +- id, src0, src1, ctrl, coef); ++ cntl = nv_rd32(dev, ctrl) & 0xfffffff2; ++ if (reg->pll) { ++ nv_mask(dev, src0, 0x00000101, 0x00000101); ++ nv_wr32(dev, coef, reg->pll); ++ nv_wr32(dev, ctrl, cntl | 0x00000015); ++ nv_mask(dev, src1, 0x00000100, 0x00000000); ++ nv_mask(dev, src1, 0x00000001, 0x00000000); ++ } else { ++ nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk); ++ nv_wr32(dev, ctrl, cntl | 0x0000001d); ++ nv_mask(dev, ctrl, 0x00000001, 0x00000000); ++ nv_mask(dev, src0, 0x00000100, 0x00000000); ++ nv_mask(dev, src0, 0x00000001, 0x00000000); ++ } ++} + +- if (ctrl & 0x00000008) { +- u32 div = ((src1 & 0x003c0000) >> 18) + 1; +- return (pll.refclk * 2) / div; ++static void ++prog_clk(struct drm_device *dev, int clk, struct creg *reg) ++{ ++ if (!reg->clk) { ++ NV_DEBUG(dev, "no clock for %02x\n", clk); ++ return; + } + +- P = (coef & 0x003f0000) >> 16; +- N = (coef & 0x0000ff00) >> 8; +- M = (coef & 0x000000ff); +- return pll.refclk * N / M / P; ++ nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk); ++} ++ ++int ++nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ perflvl->core = read_pll(dev, 0x00, 0x4200); ++ perflvl->shader = read_pll(dev, 0x01, 0x4220); ++ perflvl->memory = read_pll(dev, 0x02, 0x4000); ++ perflvl->unka0 = read_clk(dev, 0x20, false); ++ perflvl->vdec = read_clk(dev, 0x21, false); ++ perflvl->daemon = read_clk(dev, 0x25, false); ++ perflvl->copy = perflvl->core; ++ return 0; + } + ++struct nva3_pm_state { ++ struct creg nclk; ++ struct creg sclk; ++ struct creg mclk; ++ struct creg vdec; ++ struct creg unka0; ++}; ++ + void * +-nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, +- u32 id, int khz) ++nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) + { +- struct nva3_pm_state *pll; +- struct pll_lims limits; +- int N, M, P, diff; +- int ret, off; ++ struct nva3_pm_state *info; ++ int ret; + +- ret = get_pll_limits(dev, id, &limits); +- if (ret < 0) +- return (ret == -ENOENT) ? NULL : ERR_PTR(ret); ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return ERR_PTR(-ENOMEM); + +- off = nva3_pm_pll_offset(id); +- if (id < 0) +- return ERR_PTR(-EINVAL); ++ ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk); ++ if (ret < 0) ++ goto out; + ++ ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk); ++ if (ret < 0) ++ goto out; + +- pll = kzalloc(sizeof(*pll), GFP_KERNEL); +- if (!pll) +- return ERR_PTR(-ENOMEM); +- pll->type = id; +- pll->src0 = 0x004120 + (off * 4); +- pll->src1 = 0x004160 + (off * 4); +- pll->ctrl = limits.reg + 0; +- pll->coef = limits.reg + 4; ++ ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk); ++ if (ret < 0) ++ goto out; + +- /* If target clock is within [-2, 3) MHz of a divisor, we'll +- * use that instead of calculating MNP values +- */ +- pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16); +- if (pll->new_div) { +- diff = khz - ((limits.refclk * 2) / pll->new_div); +- if (diff < -2000 || diff >= 3000) +- pll->new_div = 0; +- } ++ ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0); ++ if (ret < 0) ++ goto out; + +- if (!pll->new_div) { +- ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); +- if (ret < 0) +- return ERR_PTR(ret); ++ ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec); ++ if (ret < 0) ++ goto out; + +- pll->new_pnm = (P << 16) | (N << 8) | M; +- pll->new_div = 2 - 1; +- } else { +- pll->new_pnm = 0; +- pll->new_div--; ++out: ++ if (ret < 0) { ++ kfree(info); ++ info = ERR_PTR(ret); + } ++ return info; ++} ++ ++static bool ++nva3_pm_grcp_idle(void *data) ++{ ++ struct drm_device *dev = data; + +- if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101) +- pll->old_pnm = nv_rd32(dev, pll->coef); +- return pll; ++ if (!(nv_rd32(dev, 0x400304) & 0x00000001)) ++ return true; ++ if (nv_rd32(dev, 0x400308) == 0x0050001c) ++ return true; ++ return false; + } + + void +-nva3_pm_clock_set(struct drm_device *dev, void *pre_state) ++nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) + { +- struct nva3_pm_state *pll = pre_state; +- u32 ctrl = 0; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nva3_pm_state *info = pre_state; ++ unsigned long flags; + +- /* For the memory clock, NVIDIA will build a "script" describing +- * the reclocking process and ask PDAEMON to execute it. +- */ +- if (pll->type == PLL_MEMORY) { +- nv_wr32(dev, 0x100210, 0); +- nv_wr32(dev, 0x1002dc, 1); +- nv_wr32(dev, 0x004018, 0x00001000); +- ctrl = 0x18000100; ++ /* prevent any new grctx switches from starting */ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_wr32(dev, 0x400324, 0x00000000); ++ nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */ ++ /* wait for any pending grctx switches to complete */ ++ if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) { ++ NV_ERROR(dev, "pm: ctxprog didn't go idle\n"); ++ goto cleanup; + } +- +- if (pll->old_pnm || !pll->new_pnm) { +- nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 | +- (pll->new_div << 18)); +- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); +- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); ++ /* freeze PFIFO */ ++ nv_mask(dev, 0x002504, 0x00000001, 0x00000001); ++ if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) { ++ NV_ERROR(dev, "pm: fifo didn't go idle\n"); ++ goto cleanup; + } + +- if (pll->new_pnm) { +- nv_mask(dev, pll->src0, 0x00000101, 0x00000101); +- nv_wr32(dev, pll->coef, pll->new_pnm); +- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); +- nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000); +- nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010); +- nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl); +- nv_mask(dev, pll->src1, 0x00000100, 0x00000000); +- nv_mask(dev, pll->src1, 0x00000001, 0x00000000); +- if (pll->type == PLL_MEMORY) +- nv_wr32(dev, 0x4018, 0x10005000); +- } else { +- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); +- nv_mask(dev, pll->src0, 0x00000100, 0x00000000); +- nv_mask(dev, pll->src0, 0x00000001, 0x00000000); +- if (pll->type == PLL_MEMORY) +- nv_wr32(dev, 0x4018, 0x1000d000); +- } ++ prog_pll(dev, 0x00, 0x004200, &info->nclk); ++ prog_pll(dev, 0x01, 0x004220, &info->sclk); ++ prog_clk(dev, 0x20, &info->unka0); ++ prog_clk(dev, 0x21, &info->vdec); + +- if (pll->type == PLL_MEMORY) { ++ if (info->mclk.clk || info->mclk.pll) { ++ nv_wr32(dev, 0x100210, 0); ++ nv_wr32(dev, 0x1002dc, 1); ++ nv_wr32(dev, 0x004018, 0x00001000); ++ prog_pll(dev, 0x02, 0x004000, &info->mclk); ++ if (nv_rd32(dev, 0x4000) & 0x00000008) ++ nv_wr32(dev, 0x004018, 0x1000d000); ++ else ++ nv_wr32(dev, 0x004018, 0x10005000); + nv_wr32(dev, 0x1002dc, 0); + nv_wr32(dev, 0x100210, 0x80000000); + } + +- kfree(pll); ++cleanup: ++ /* unfreeze PFIFO */ ++ nv_mask(dev, 0x002504, 0x00000001, 0x00000000); ++ /* restore ctxprog to normal */ ++ nv_wr32(dev, 0x400324, 0x00000000); ++ nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */ ++ /* unblock it if necessary */ ++ if (nv_rd32(dev, 0x400308) == 0x0050001c) ++ nv_mask(dev, 0x400824, 0x10000000, 0x10000000); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ kfree(info); + } +- +diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c +index 08e6b11..5bf5503 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_fb.c ++++ b/drivers/gpu/drm/nouveau/nvc0_fb.c +@@ -32,6 +32,30 @@ struct nvc0_fb_priv { + dma_addr_t r100c10; + }; + ++static inline void ++nvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp) ++{ ++ u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); ++ u32 stat = nv_rd32(dev, subp_base + 0x020); ++ ++ if (stat) { ++ NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat); ++ nv_wr32(dev, subp_base + 0x020, stat); ++ } ++} ++ ++static void ++nvc0_mfb_isr(struct drm_device *dev) ++{ ++ u32 units = nv_rd32(dev, 0x00017c); ++ while (units) { ++ u32 subp, unit = ffs(units) - 1; ++ for (subp = 0; subp < 2; subp++) ++ nvc0_mfb_subp_isr(dev, unit, subp); ++ units &= ~(1 << unit); ++ } ++} ++ + static void + nvc0_fb_destroy(struct drm_device *dev) + { +@@ -39,6 +63,8 @@ nvc0_fb_destroy(struct drm_device *dev) + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nvc0_fb_priv *priv = pfb->priv; + ++ nouveau_irq_unregister(dev, 25); ++ + if (priv->r100c10_page) { + pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); +@@ -74,6 +100,7 @@ nvc0_fb_create(struct drm_device *dev) + return -EFAULT; + } + ++ nouveau_irq_register(dev, 25, nvc0_mfb_isr); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c +index 6f9f341..dcbe0d5 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c ++++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c +@@ -322,7 +322,7 @@ nvc0_fifo_init(struct drm_device *dev) + } + + /* PSUBFIFO[n] */ +- for (i = 0; i < 3; i++) { ++ for (i = 0; i < priv->spoon_nr; i++) { + nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ +diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c +index 5b2f6f4..4b8d0b3 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_graph.c ++++ b/drivers/gpu/drm/nouveau/nvc0_graph.c +@@ -390,7 +390,7 @@ nvc0_graph_init_gpc_0(struct drm_device *dev) + } + + nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); +- nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); ++ nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); + } + + static void +@@ -700,22 +700,6 @@ nvc0_graph_isr(struct drm_device *dev) + nv_wr32(dev, 0x400500, 0x00010001); + } + +-static void +-nvc0_runk140_isr(struct drm_device *dev) +-{ +- u32 units = nv_rd32(dev, 0x00017c) & 0x1f; +- +- while (units) { +- u32 unit = ffs(units) - 1; +- u32 reg = 0x140000 + unit * 0x2000; +- u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0); +- u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0); +- +- NV_DEBUG(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); +- units &= ~(1 << unit); +- } +-} +- + static int + nvc0_graph_create_fw(struct drm_device *dev, const char *fwname, + struct nvc0_graph_fuc *fuc) +@@ -764,7 +748,6 @@ nvc0_graph_destroy(struct drm_device *dev, int engine) + } + + nouveau_irq_unregister(dev, 12); +- nouveau_irq_unregister(dev, 25); + + nouveau_gpuobj_ref(NULL, &priv->unk4188b8); + nouveau_gpuobj_ref(NULL, &priv->unk4188b4); +@@ -803,7 +786,6 @@ nvc0_graph_create(struct drm_device *dev) + + NVOBJ_ENGINE_ADD(dev, GR, &priv->base); + nouveau_irq_register(dev, 12, nvc0_graph_isr); +- nouveau_irq_register(dev, 25, nvc0_runk140_isr); + + if (nouveau_ctxfw) { + NV_INFO(dev, "PGRAPH: using external firmware\n"); +@@ -864,6 +846,9 @@ nvc0_graph_create(struct drm_device *dev) + case 0xce: /* 4/4/0/0, 4 */ + priv->magic_not_rop_nr = 0x03; + break; ++ case 0xcf: /* 4/0/0/0, 3 */ ++ priv->magic_not_rop_nr = 0x03; ++ break; + } + + if (!priv->magic_not_rop_nr) { +@@ -889,20 +874,3 @@ error: + nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); + return ret; + } +- +-MODULE_FIRMWARE("nouveau/nvc0_fuc409c"); +-MODULE_FIRMWARE("nouveau/nvc0_fuc409d"); +-MODULE_FIRMWARE("nouveau/nvc0_fuc41ac"); +-MODULE_FIRMWARE("nouveau/nvc0_fuc41ad"); +-MODULE_FIRMWARE("nouveau/nvc3_fuc409c"); +-MODULE_FIRMWARE("nouveau/nvc3_fuc409d"); +-MODULE_FIRMWARE("nouveau/nvc3_fuc41ac"); +-MODULE_FIRMWARE("nouveau/nvc3_fuc41ad"); +-MODULE_FIRMWARE("nouveau/nvc4_fuc409c"); +-MODULE_FIRMWARE("nouveau/nvc4_fuc409d"); +-MODULE_FIRMWARE("nouveau/nvc4_fuc41ac"); +-MODULE_FIRMWARE("nouveau/nvc4_fuc41ad"); +-MODULE_FIRMWARE("nouveau/fuc409c"); +-MODULE_FIRMWARE("nouveau/fuc409d"); +-MODULE_FIRMWARE("nouveau/fuc41ac"); +-MODULE_FIRMWARE("nouveau/fuc41ad"); +diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h +index 55689e9..636fe98 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_graph.h ++++ b/drivers/gpu/drm/nouveau/nvc0_graph.h +@@ -82,6 +82,7 @@ nvc0_graph_class(struct drm_device *dev) + case 0xc3: + case 0xc4: + case 0xce: /* guess, mmio trace shows only 0x9097 state */ ++ case 0xcf: /* guess, mmio trace shows only 0x9097 state */ + return 0x9097; + case 0xc1: + return 0x9197; +diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c +index 31018ea..dd0e6a7 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grctx.c ++++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c +@@ -1678,7 +1678,10 @@ nvc0_grctx_generate_tp(struct drm_device *dev) + nv_wr32(dev, 0x419c04, 0x00000006); + nv_wr32(dev, 0x419c08, 0x00000002); + nv_wr32(dev, 0x419c20, 0x00000000); +- nv_wr32(dev, 0x419cb0, 0x00060048); //XXX: 0xce 0x00020048 ++ if (chipset == 0xce || chipset == 0xcf) ++ nv_wr32(dev, 0x419cb0, 0x00020048); ++ else ++ nv_wr32(dev, 0x419cb0, 0x00060048); + nv_wr32(dev, 0x419ce8, 0x00000000); + nv_wr32(dev, 0x419cf4, 0x00000183); + nv_wr32(dev, 0x419d20, chipset != 0xc1 ? 0x02180000 : 0x12180000); +@@ -1783,11 +1786,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) + nv_wr32(dev, 0x40587c, 0x00000000); + + if (1) { +- const u8 chipset_tp_max[] = { 16, 4, 0, 4, 8, 0, 0, 0, +- 16, 0, 0, 0, 0, 0, 8, 0 }; +- u8 max = chipset_tp_max[dev_priv->chipset & 0x0f]; +- u8 tpnr[GPC_MAX]; +- u8 data[TP_MAX]; ++ u8 tpnr[GPC_MAX], data[TP_MAX]; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + memset(data, 0x1f, sizeof(data)); +@@ -1801,7 +1800,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) + data[tp] = gpc; + } + +- for (i = 0; i < max / 4; i++) ++ for (i = 0; i < 4; i++) + nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + } + +diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc +index 0ec2add..06f5e26 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc ++++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc +@@ -77,6 +77,11 @@ chipsets: + .b16 nvc0_gpc_mmio_tail + .b16 nvc0_tpc_mmio_head + .b16 nvc3_tpc_mmio_tail ++.b8 0xcf 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvcf_tpc_mmio_tail + .b8 0 0 0 0 + + // GPC mmio lists +@@ -134,8 +139,9 @@ mmctx_data(0x000750, 2) + nvc0_tpc_mmio_tail: + mmctx_data(0x000758, 1) + mmctx_data(0x0002c4, 1) +-mmctx_data(0x0004bc, 1) + mmctx_data(0x0006e0, 1) ++nvcf_tpc_mmio_tail: ++mmctx_data(0x0004bc, 1) + nvc3_tpc_mmio_tail: + mmctx_data(0x000544, 1) + nvc1_tpc_mmio_tail: +diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h +index 1896c89..6f82032 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h ++++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h +@@ -25,23 +25,26 @@ uint32_t nvc0_grgpc_data[] = { + 0x00000000, + 0x00000000, + 0x000000c0, +- 0x011000b0, +- 0x01640114, ++ 0x011c00bc, ++ 0x01700120, + 0x000000c1, +- 0x011400b0, +- 0x01780114, ++ 0x012000bc, ++ 0x01840120, + 0x000000c3, +- 0x011000b0, +- 0x01740114, ++ 0x011c00bc, ++ 0x01800120, + 0x000000c4, +- 0x011000b0, +- 0x01740114, ++ 0x011c00bc, ++ 0x01800120, + 0x000000c8, +- 0x011000b0, +- 0x01640114, ++ 0x011c00bc, ++ 0x01700120, + 0x000000ce, +- 0x011000b0, +- 0x01740114, ++ 0x011c00bc, ++ 0x01800120, ++ 0x000000cf, ++ 0x011c00bc, ++ 0x017c0120, + 0x00000000, + 0x00000380, + 0x14000400, +@@ -90,8 +93,8 @@ uint32_t nvc0_grgpc_data[] = { + 0x04000750, + 0x00000758, + 0x000002c4, +- 0x000004bc, + 0x000006e0, ++ 0x000004bc, + 0x00000544, + }; + +diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc +index a1a5991..e4f8c7e 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc ++++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc +@@ -56,6 +56,9 @@ chipsets: + .b8 0xce 0 0 0 + .b16 nvc0_hub_mmio_head + .b16 nvc0_hub_mmio_tail ++.b8 0xcf 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail + .b8 0 0 0 0 + + nvc0_hub_mmio_head: +diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h +index b3b541b..241d326 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h ++++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h +@@ -23,17 +23,19 @@ uint32_t nvc0_grhub_data[] = { + 0x00000000, + 0x00000000, + 0x000000c0, +- 0x012c0090, ++ 0x01340098, + 0x000000c1, +- 0x01300090, ++ 0x01380098, + 0x000000c3, +- 0x012c0090, ++ 0x01340098, + 0x000000c4, +- 0x012c0090, ++ 0x01340098, + 0x000000c8, +- 0x012c0090, ++ 0x01340098, + 0x000000ce, +- 0x012c0090, ++ 0x01340098, ++ 0x000000cf, ++ 0x01340098, + 0x00000000, + 0x0417e91c, + 0x04400204, +@@ -190,8 +192,6 @@ uint32_t nvc0_grhub_data[] = { + 0x00000000, + 0x00000000, + 0x00000000, +- 0x00000000, +- 0x00000000, + }; + + uint32_t nvc0_grhub_code[] = { +diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c +new file mode 100644 +index 0000000..929aded +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvc0_pm.c +@@ -0,0 +1,155 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_bios.h" ++#include "nouveau_pm.h" ++ ++static u32 read_div(struct drm_device *, int, u32, u32); ++static u32 read_pll(struct drm_device *, u32); ++ ++static u32 ++read_vco(struct drm_device *dev, u32 dsrc) ++{ ++ u32 ssrc = nv_rd32(dev, dsrc); ++ if (!(ssrc & 0x00000100)) ++ return read_pll(dev, 0x00e800); ++ return read_pll(dev, 0x00e820); ++} ++ ++static u32 ++read_pll(struct drm_device *dev, u32 pll) ++{ ++ u32 ctrl = nv_rd32(dev, pll + 0); ++ u32 coef = nv_rd32(dev, pll + 4); ++ u32 P = (coef & 0x003f0000) >> 16; ++ u32 N = (coef & 0x0000ff00) >> 8; ++ u32 M = (coef & 0x000000ff) >> 0; ++ u32 sclk, doff; ++ ++ if (!(ctrl & 0x00000001)) ++ return 0; ++ ++ switch (pll & 0xfff000) { ++ case 0x00e000: ++ sclk = 27000; ++ P = 1; ++ break; ++ case 0x137000: ++ doff = (pll - 0x137000) / 0x20; ++ sclk = read_div(dev, doff, 0x137120, 0x137140); ++ break; ++ case 0x132000: ++ switch (pll) { ++ case 0x132000: ++ sclk = read_pll(dev, 0x132020); ++ break; ++ case 0x132020: ++ sclk = read_div(dev, 0, 0x137320, 0x137330); ++ break; ++ default: ++ return 0; ++ } ++ break; ++ default: ++ return 0; ++ } ++ ++ return sclk * N / M / P; ++} ++ ++static u32 ++read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) ++{ ++ u32 ssrc = nv_rd32(dev, dsrc + (doff * 4)); ++ u32 sctl = nv_rd32(dev, dctl + (doff * 4)); ++ ++ switch (ssrc & 0x00000003) { ++ case 0: ++ if ((ssrc & 0x00030000) != 0x00030000) ++ return 27000; ++ return 108000; ++ case 2: ++ return 100000; ++ case 3: ++ if (sctl & 0x80000000) { ++ u32 sclk = read_vco(dev, dsrc + (doff * 4)); ++ u32 sdiv = (sctl & 0x0000003f) + 2; ++ return (sclk * 2) / sdiv; ++ } ++ ++ return read_vco(dev, dsrc + (doff * 4)); ++ default: ++ return 0; ++ } ++} ++ ++static u32 ++read_mem(struct drm_device *dev) ++{ ++ u32 ssel = nv_rd32(dev, 0x1373f0); ++ if (ssel & 0x00000001) ++ return read_div(dev, 0, 0x137300, 0x137310); ++ return read_pll(dev, 0x132000); ++} ++ ++static u32 ++read_clk(struct drm_device *dev, int clk) ++{ ++ u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4)); ++ u32 ssel = nv_rd32(dev, 0x137100); ++ u32 sclk, sdiv; ++ ++ if (ssel & (1 << clk)) { ++ if (clk < 7) ++ sclk = read_pll(dev, 0x137000 + (clk * 0x20)); ++ else ++ sclk = read_pll(dev, 0x1370e0); ++ sdiv = ((sctl & 0x00003f00) >> 8) + 2; ++ } else { ++ sclk = read_div(dev, clk, 0x137160, 0x1371d0); ++ sdiv = ((sctl & 0x0000003f) >> 0) + 2; ++ } ++ ++ if (sctl & 0x80000000) ++ return (sclk * 2) / sdiv; ++ return sclk; ++} ++ ++int ++nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ perflvl->shader = read_clk(dev, 0x00); ++ perflvl->core = perflvl->shader / 2; ++ perflvl->memory = read_mem(dev); ++ perflvl->rop = read_clk(dev, 0x01); ++ perflvl->hub07 = read_clk(dev, 0x02); ++ perflvl->hub06 = read_clk(dev, 0x07); ++ perflvl->hub01 = read_clk(dev, 0x08); ++ perflvl->copy = read_clk(dev, 0x09); ++ perflvl->daemon = read_clk(dev, 0x0c); ++ perflvl->vdec = read_clk(dev, 0x0e); ++ return 0; ++} +diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c +index e45a24d..edbfe93 100644 +--- a/drivers/gpu/drm/nouveau/nvc0_vram.c ++++ b/drivers/gpu/drm/nouveau/nvc0_vram.c +@@ -61,7 +61,7 @@ nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, + u32 type, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_mm *mm = dev_priv->engine.vram.mm; ++ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int ret; +@@ -106,12 +106,50 @@ nvc0_vram_init(struct drm_device *dev) + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ +- u32 length; ++ u32 parts = nv_rd32(dev, 0x121c74); ++ u32 bsize = nv_rd32(dev, 0x10f20c); ++ u32 offset, length; ++ bool uniform = true; ++ int ret, i; + +- dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; +- dev_priv->vram_size *= nv_rd32(dev, 0x121c74); ++ NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); ++ NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize); + +- length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; ++ /* read amount of vram attached to each memory controller */ ++ for (i = 0; i < parts; i++) { ++ u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000)); ++ if (psize != bsize) { ++ if (psize < bsize) ++ bsize = psize; ++ uniform = false; ++ } ++ ++ NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize); ++ ++ dev_priv->vram_size += (u64)psize << 20; ++ } ++ ++ /* if all controllers have the same amount attached, there's no holes */ ++ if (uniform) { ++ offset = rsvd_head; ++ length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; ++ return nouveau_mm_init(&vram->mm, offset, length, 1); ++ } + +- return nouveau_mm_init(&vram->mm, rsvd_head, length, 1); ++ /* otherwise, address lowest common amount from 0GiB */ ++ ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1); ++ if (ret) ++ return ret; ++ ++ /* and the rest starting from (8GiB + common_size) */ ++ offset = (0x0200000000ULL >> 12) + (bsize << 8); ++ length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail; ++ ++ ret = nouveau_mm_init(&vram->mm, offset, length, 0); ++ if (ret) { ++ nouveau_mm_fini(&vram->mm); ++ return ret; ++ } ++ ++ return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c +new file mode 100644 +index 0000000..23d63b4 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvd0_display.c +@@ -0,0 +1,1473 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include ++ ++#include "drmP.h" ++#include "drm_crtc_helper.h" ++ ++#include "nouveau_drv.h" ++#include "nouveau_connector.h" ++#include "nouveau_encoder.h" ++#include "nouveau_crtc.h" ++#include "nouveau_dma.h" ++#include "nouveau_fb.h" ++#include "nv50_display.h" ++ ++struct nvd0_display { ++ struct nouveau_gpuobj *mem; ++ struct { ++ dma_addr_t handle; ++ u32 *ptr; ++ } evo[1]; ++ ++ struct tasklet_struct tasklet; ++ u32 modeset; ++}; ++ ++static struct nvd0_display * ++nvd0_display(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ return dev_priv->engine.display.priv; ++} ++ ++static inline int ++evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data) ++{ ++ int ret = 0; ++ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001); ++ nv_wr32(dev, 0x610704 + (id * 0x10), data); ++ nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd); ++ if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000)) ++ ret = -EBUSY; ++ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000); ++ return ret; ++} ++ ++static u32 * ++evo_wait(struct drm_device *dev, int id, int nr) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4; ++ ++ if (put + nr >= (PAGE_SIZE / 4)) { ++ disp->evo[id].ptr[put] = 0x20000000; ++ ++ nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000); ++ if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) { ++ NV_ERROR(dev, "evo %d dma stalled\n", id); ++ return NULL; ++ } ++ ++ put = 0; ++ } ++ ++ return disp->evo[id].ptr + put; ++} ++ ++static void ++evo_kick(u32 *push, struct drm_device *dev, int id) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2); ++} ++ ++#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) ++#define evo_data(p,d) *((p)++) = (d) ++ ++static struct drm_crtc * ++nvd0_display_crtc_get(struct drm_encoder *encoder) ++{ ++ return nouveau_encoder(encoder)->crtc; ++} ++ ++/****************************************************************************** ++ * CRTC ++ *****************************************************************************/ ++static int ++nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) ++{ ++ struct drm_device *dev = nv_crtc->base.dev; ++ u32 *push, mode; ++ ++ mode = 0x00000000; ++ if (on) { ++ /* 0x11: 6bpc dynamic 2x2 ++ * 0x13: 8bpc dynamic 2x2 ++ * 0x19: 6bpc static 2x2 ++ * 0x1b: 8bpc static 2x2 ++ * 0x21: 6bpc temporal ++ * 0x23: 8bpc temporal ++ */ ++ mode = 0x00000011; ++ } ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, mode); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, dev, 0); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update) ++{ ++ struct drm_display_mode *mode = &nv_crtc->base.mode; ++ struct drm_device *dev = nv_crtc->base.dev; ++ struct nouveau_connector *nv_connector; ++ u32 *push, outX, outY; ++ ++ outX = mode->hdisplay; ++ outY = mode->vdisplay; ++ ++ nv_connector = nouveau_crtc_connector_get(nv_crtc); ++ if (nv_connector && nv_connector->native_mode) { ++ struct drm_display_mode *native = nv_connector->native_mode; ++ u32 xratio = (native->hdisplay << 19) / mode->hdisplay; ++ u32 yratio = (native->vdisplay << 19) / mode->vdisplay; ++ ++ switch (type) { ++ case DRM_MODE_SCALE_ASPECT: ++ if (xratio > yratio) { ++ outX = (mode->hdisplay * yratio) >> 19; ++ outY = (mode->vdisplay * yratio) >> 19; ++ } else { ++ outX = (mode->hdisplay * xratio) >> 19; ++ outY = (mode->vdisplay * xratio) >> 19; ++ } ++ break; ++ case DRM_MODE_SCALE_FULLSCREEN: ++ outX = native->hdisplay; ++ outY = native->vdisplay; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ push = evo_wait(dev, 0, 16); ++ if (push) { ++ evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); ++ evo_data(push, (outY << 16) | outX); ++ evo_data(push, (outY << 16) | outX); ++ evo_data(push, (outY << 16) | outX); ++ evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, (mode->vdisplay << 16) | mode->hdisplay); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, dev, 0); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, ++ int x, int y, bool update) ++{ ++ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); ++ u32 *push; ++ ++ push = evo_wait(fb->dev, 0, 16); ++ if (push) { ++ evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, nvfb->nvbo->bo.offset >> 8); ++ evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); ++ evo_data(push, (fb->height << 16) | fb->width); ++ evo_data(push, nvfb->r_pitch); ++ evo_data(push, nvfb->r_format); ++ evo_data(push, nvfb->r_dma); ++ evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, (y << 16) | x); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, fb->dev, 0); ++ } ++ ++ nv_crtc->fb.tile_flags = nvfb->r_dma; ++ return 0; ++} ++ ++static void ++nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update) ++{ ++ struct drm_device *dev = nv_crtc->base.dev; ++ u32 *push = evo_wait(dev, 0, 16); ++ if (push) { ++ if (show) { ++ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); ++ evo_data(push, 0x85000000); ++ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); ++ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, NvEvoVRAM); ++ } else { ++ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x05000000); ++ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ } ++ ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ ++ evo_kick(push, dev, 0); ++ } ++} ++ ++static void ++nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) ++{ ++} ++ ++static void ++nvd0_crtc_prepare(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 *push; ++ ++ push = evo_wait(crtc->dev, 0, 2); ++ if (push) { ++ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x03000000); ++ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nvd0_crtc_cursor_show(nv_crtc, false, false); ++} ++ ++static void ++nvd0_crtc_commit(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 *push; ++ ++ push = evo_wait(crtc->dev, 0, 32); ++ if (push) { ++ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, nv_crtc->fb.tile_flags); ++ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); ++ evo_data(push, 0x83000000); ++ evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); ++ evo_data(push, 0x00000000); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, NvEvoVRAM); ++ evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0xffffff00); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true); ++} ++ ++static bool ++nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++static int ++nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); ++ int ret; ++ ++ ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); ++ if (ret) ++ return ret; ++ ++ if (old_fb) { ++ nvfb = nouveau_framebuffer(old_fb); ++ nouveau_bo_unpin(nvfb->nvbo); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, ++ struct drm_display_mode *mode, int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct nouveau_connector *nv_connector; ++ u32 htotal = mode->htotal; ++ u32 vtotal = mode->vtotal; ++ u32 hsyncw = mode->hsync_end - mode->hsync_start - 1; ++ u32 vsyncw = mode->vsync_end - mode->vsync_start - 1; ++ u32 hfrntp = mode->hsync_start - mode->hdisplay; ++ u32 vfrntp = mode->vsync_start - mode->vdisplay; ++ u32 hbackp = mode->htotal - mode->hsync_end; ++ u32 vbackp = mode->vtotal - mode->vsync_end; ++ u32 hss2be = hsyncw + hbackp; ++ u32 vss2be = vsyncw + vbackp; ++ u32 hss2de = htotal - hfrntp; ++ u32 vss2de = vtotal - vfrntp; ++ u32 syncs, *push; ++ int ret; ++ ++ syncs = 0x00000001; ++ if (mode->flags & DRM_MODE_FLAG_NHSYNC) ++ syncs |= 0x00000008; ++ if (mode->flags & DRM_MODE_FLAG_NVSYNC) ++ syncs |= 0x00000010; ++ ++ ret = nvd0_crtc_swap_fbs(crtc, old_fb); ++ if (ret) ++ return ret; ++ ++ push = evo_wait(crtc->dev, 0, 64); ++ if (push) { ++ evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5); ++ evo_data(push, 0x00000000); ++ evo_data(push, (vtotal << 16) | htotal); ++ evo_data(push, (vsyncw << 16) | hsyncw); ++ evo_data(push, (vss2be << 16) | hss2be); ++ evo_data(push, (vss2de << 16) | hss2de); ++ evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); /* ??? */ ++ evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); ++ evo_data(push, mode->clock * 1000); ++ evo_data(push, 0x00200000); /* ??? */ ++ evo_data(push, mode->clock * 1000); ++ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, syncs); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nv_connector = nouveau_crtc_connector_get(nv_crtc); ++ nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false); ++ nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false); ++ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false); ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ int ret; ++ ++ if (!crtc->fb) { ++ NV_DEBUG_KMS(crtc->dev, "No FB bound\n"); ++ return 0; ++ } ++ ++ ret = nvd0_crtc_swap_fbs(crtc, old_fb); ++ if (ret) ++ return ret; ++ ++ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true); ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, int x, int y, ++ enum mode_set_atomic state) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ nvd0_crtc_set_image(nv_crtc, fb, x, y, true); ++ return 0; ++} ++ ++static void ++nvd0_crtc_lut_load(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo); ++ int i; ++ ++ for (i = 0; i < 256; i++) { ++ writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0); ++ writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2); ++ writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4); ++ } ++} ++ ++static int ++nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, ++ uint32_t handle, uint32_t width, uint32_t height) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ struct drm_gem_object *gem; ++ struct nouveau_bo *nvbo; ++ bool visible = (handle != 0); ++ int i, ret = 0; ++ ++ if (visible) { ++ if (width != 64 || height != 64) ++ return -EINVAL; ++ ++ gem = drm_gem_object_lookup(dev, file_priv, handle); ++ if (unlikely(!gem)) ++ return -ENOENT; ++ nvbo = nouveau_gem_object(gem); ++ ++ ret = nouveau_bo_map(nvbo); ++ if (ret == 0) { ++ for (i = 0; i < 64 * 64; i++) { ++ u32 v = nouveau_bo_rd32(nvbo, i); ++ nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); ++ } ++ nouveau_bo_unmap(nvbo); ++ } ++ ++ drm_gem_object_unreference_unlocked(gem); ++ } ++ ++ if (visible != nv_crtc->cursor.visible) { ++ nvd0_crtc_cursor_show(nv_crtc, visible, true); ++ nv_crtc->cursor.visible = visible; ++ } ++ ++ return ret; ++} ++ ++static int ++nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ const u32 data = (y << 16) | x; ++ ++ nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data); ++ nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000); ++ return 0; ++} ++ ++static void ++nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, ++ uint32_t start, uint32_t size) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 end = max(start + size, (u32)256); ++ u32 i; ++ ++ for (i = start; i < end; i++) { ++ nv_crtc->lut.r[i] = r[i]; ++ nv_crtc->lut.g[i] = g[i]; ++ nv_crtc->lut.b[i] = b[i]; ++ } ++ ++ nvd0_crtc_lut_load(crtc); ++} ++ ++static void ++nvd0_crtc_destroy(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ nouveau_bo_unmap(nv_crtc->cursor.nvbo); ++ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); ++ nouveau_bo_unmap(nv_crtc->lut.nvbo); ++ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); ++ drm_crtc_cleanup(crtc); ++ kfree(crtc); ++} ++ ++static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = { ++ .dpms = nvd0_crtc_dpms, ++ .prepare = nvd0_crtc_prepare, ++ .commit = nvd0_crtc_commit, ++ .mode_fixup = nvd0_crtc_mode_fixup, ++ .mode_set = nvd0_crtc_mode_set, ++ .mode_set_base = nvd0_crtc_mode_set_base, ++ .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic, ++ .load_lut = nvd0_crtc_lut_load, ++}; ++ ++static const struct drm_crtc_funcs nvd0_crtc_func = { ++ .cursor_set = nvd0_crtc_cursor_set, ++ .cursor_move = nvd0_crtc_cursor_move, ++ .gamma_set = nvd0_crtc_gamma_set, ++ .set_config = drm_crtc_helper_set_config, ++ .destroy = nvd0_crtc_destroy, ++}; ++ ++static void ++nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) ++{ ++} ++ ++static void ++nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) ++{ ++} ++ ++static int ++nvd0_crtc_create(struct drm_device *dev, int index) ++{ ++ struct nouveau_crtc *nv_crtc; ++ struct drm_crtc *crtc; ++ int ret, i; ++ ++ nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); ++ if (!nv_crtc) ++ return -ENOMEM; ++ ++ nv_crtc->index = index; ++ nv_crtc->set_dither = nvd0_crtc_set_dither; ++ nv_crtc->set_scale = nvd0_crtc_set_scale; ++ nv_crtc->cursor.set_offset = nvd0_cursor_set_offset; ++ nv_crtc->cursor.set_pos = nvd0_cursor_set_pos; ++ for (i = 0; i < 256; i++) { ++ nv_crtc->lut.r[i] = i << 8; ++ nv_crtc->lut.g[i] = i << 8; ++ nv_crtc->lut.b[i] = i << 8; ++ } ++ ++ crtc = &nv_crtc->base; ++ drm_crtc_init(dev, crtc, &nvd0_crtc_func); ++ drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc); ++ drm_mode_crtc_set_gamma_size(crtc, 256); ++ ++ ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, ++ 0, 0x0000, &nv_crtc->cursor.nvbo); ++ if (!ret) { ++ ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); ++ if (!ret) ++ ret = nouveau_bo_map(nv_crtc->cursor.nvbo); ++ if (ret) ++ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); ++ } ++ ++ if (ret) ++ goto out; ++ ++ ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, ++ 0, 0x0000, &nv_crtc->lut.nvbo); ++ if (!ret) { ++ ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); ++ if (!ret) ++ ret = nouveau_bo_map(nv_crtc->lut.nvbo); ++ if (ret) ++ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); ++ } ++ ++ if (ret) ++ goto out; ++ ++ nvd0_crtc_lut_load(crtc); ++ ++out: ++ if (ret) ++ nvd0_crtc_destroy(crtc); ++ return ret; ++} ++ ++/****************************************************************************** ++ * DAC ++ *****************************************************************************/ ++static void ++nvd0_dac_dpms(struct drm_encoder *encoder, int mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ int or = nv_encoder->or; ++ u32 dpms_ctrl; ++ ++ dpms_ctrl = 0x80000000; ++ if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) ++ dpms_ctrl |= 0x00000001; ++ if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) ++ dpms_ctrl |= 0x00000004; ++ ++ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); ++ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); ++} ++ ++static bool ++nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_connector *nv_connector; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (nv_connector && nv_connector->native_mode) { ++ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { ++ int id = adjusted_mode->base.id; ++ *adjusted_mode = *nv_connector->native_mode; ++ adjusted_mode->base.id = id; ++ } ++ } ++ ++ return true; ++} ++ ++static void ++nvd0_dac_prepare(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_dac_commit(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); ++ u32 *push; ++ ++ nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON); ++ ++ push = evo_wait(encoder->dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2); ++ evo_data(push, 1 << nv_crtc->index); ++ evo_data(push, 0x00ff); ++ evo_kick(push, encoder->dev, 0); ++ } ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static void ++nvd0_dac_disconnect(struct drm_encoder *encoder) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ u32 *push; ++ ++ if (nv_encoder->crtc) { ++ nvd0_crtc_prepare(nv_encoder->crtc); ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ } ++ ++ nv_encoder->crtc = NULL; ++ } ++} ++ ++static enum drm_connector_status ++nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) ++{ ++ enum drm_connector_status status = connector_status_disconnected; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ int or = nv_encoder->or; ++ u32 load; ++ ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000); ++ udelay(9500); ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000); ++ ++ load = nv_rd32(dev, 0x61a00c + (or * 0x800)); ++ if ((load & 0x38000000) == 0x38000000) ++ status = connector_status_connected; ++ ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000); ++ return status; ++} ++ ++static void ++nvd0_dac_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++ kfree(encoder); ++} ++ ++static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = { ++ .dpms = nvd0_dac_dpms, ++ .mode_fixup = nvd0_dac_mode_fixup, ++ .prepare = nvd0_dac_prepare, ++ .commit = nvd0_dac_commit, ++ .mode_set = nvd0_dac_mode_set, ++ .disable = nvd0_dac_disconnect, ++ .get_crtc = nvd0_display_crtc_get, ++ .detect = nvd0_dac_detect ++}; ++ ++static const struct drm_encoder_funcs nvd0_dac_func = { ++ .destroy = nvd0_dac_destroy, ++}; ++ ++static int ++nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe) ++{ ++ struct drm_device *dev = connector->dev; ++ struct nouveau_encoder *nv_encoder; ++ struct drm_encoder *encoder; ++ ++ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); ++ if (!nv_encoder) ++ return -ENOMEM; ++ nv_encoder->dcb = dcbe; ++ nv_encoder->or = ffs(dcbe->or) - 1; ++ ++ encoder = to_drm_encoder(nv_encoder); ++ encoder->possible_crtcs = dcbe->heads; ++ encoder->possible_clones = 0; ++ drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC); ++ drm_encoder_helper_add(encoder, &nvd0_dac_hfunc); ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ return 0; ++} ++ ++/****************************************************************************** ++ * SOR ++ *****************************************************************************/ ++static void ++nvd0_sor_dpms(struct drm_encoder *encoder, int mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ struct drm_encoder *partner; ++ int or = nv_encoder->or; ++ u32 dpms_ctrl; ++ ++ nv_encoder->last_dpms = mode; ++ ++ list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { ++ struct nouveau_encoder *nv_partner = nouveau_encoder(partner); ++ ++ if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) ++ continue; ++ ++ if (nv_partner != nv_encoder && ++ nv_partner->dcb->or == nv_encoder->or) { ++ if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) ++ return; ++ break; ++ } ++ } ++ ++ dpms_ctrl = (mode == DRM_MODE_DPMS_ON); ++ dpms_ctrl |= 0x80000000; ++ ++ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); ++ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); ++} ++ ++static bool ++nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_connector *nv_connector; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (nv_connector && nv_connector->native_mode) { ++ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { ++ int id = adjusted_mode->base.id; ++ *adjusted_mode = *nv_connector->native_mode; ++ adjusted_mode->base.id = id; ++ } ++ } ++ ++ return true; ++} ++ ++static void ++nvd0_sor_prepare(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_sor_commit(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, ++ struct drm_display_mode *mode) ++{ ++ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); ++ struct nouveau_connector *nv_connector; ++ struct nvbios *bios = &dev_priv->vbios; ++ u32 mode_ctrl = (1 << nv_crtc->index); ++ u32 *push, or_config; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ switch (nv_encoder->dcb->type) { ++ case OUTPUT_TMDS: ++ if (nv_encoder->dcb->sorconf.link & 1) { ++ if (mode->clock < 165000) ++ mode_ctrl |= 0x00000100; ++ else ++ mode_ctrl |= 0x00000500; ++ } else { ++ mode_ctrl |= 0x00000200; ++ } ++ ++ or_config = (mode_ctrl & 0x00000f00) >> 8; ++ if (mode->clock >= 165000) ++ or_config |= 0x0100; ++ break; ++ case OUTPUT_LVDS: ++ or_config = (mode_ctrl & 0x00000f00) >> 8; ++ if (bios->fp_no_ddc) { ++ if (bios->fp.dual_link) ++ or_config |= 0x0100; ++ if (bios->fp.if_is_24bit) ++ or_config |= 0x0200; ++ } else { ++ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) { ++ if (((u8 *)nv_connector->edid)[121] == 2) ++ or_config |= 0x0100; ++ } else ++ if (mode->clock >= bios->fp.duallink_transition_clk) { ++ or_config |= 0x0100; ++ } ++ ++ if (or_config & 0x0100) { ++ if (bios->fp.strapless_is_24bit & 2) ++ or_config |= 0x0200; ++ } else { ++ if (bios->fp.strapless_is_24bit & 1) ++ or_config |= 0x0200; ++ } ++ ++ if (nv_connector->base.display_info.bpc == 8) ++ or_config |= 0x0200; ++ ++ } ++ break; ++ default: ++ BUG_ON(1); ++ break; ++ } ++ ++ nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); ++ ++ push = evo_wait(encoder->dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); ++ evo_data(push, mode_ctrl); ++ evo_data(push, or_config); ++ evo_kick(push, encoder->dev, 0); ++ } ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static void ++nvd0_sor_disconnect(struct drm_encoder *encoder) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ u32 *push; ++ ++ if (nv_encoder->crtc) { ++ nvd0_crtc_prepare(nv_encoder->crtc); ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ } ++ ++ nv_encoder->crtc = NULL; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; ++ } ++} ++ ++static void ++nvd0_sor_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++ kfree(encoder); ++} ++ ++static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = { ++ .dpms = nvd0_sor_dpms, ++ .mode_fixup = nvd0_sor_mode_fixup, ++ .prepare = nvd0_sor_prepare, ++ .commit = nvd0_sor_commit, ++ .mode_set = nvd0_sor_mode_set, ++ .disable = nvd0_sor_disconnect, ++ .get_crtc = nvd0_display_crtc_get, ++}; ++ ++static const struct drm_encoder_funcs nvd0_sor_func = { ++ .destroy = nvd0_sor_destroy, ++}; ++ ++static int ++nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe) ++{ ++ struct drm_device *dev = connector->dev; ++ struct nouveau_encoder *nv_encoder; ++ struct drm_encoder *encoder; ++ ++ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); ++ if (!nv_encoder) ++ return -ENOMEM; ++ nv_encoder->dcb = dcbe; ++ nv_encoder->or = ffs(dcbe->or) - 1; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; ++ ++ encoder = to_drm_encoder(nv_encoder); ++ encoder->possible_crtcs = dcbe->heads; ++ encoder->possible_clones = 0; ++ drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS); ++ drm_encoder_helper_add(encoder, &nvd0_sor_hfunc); ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ return 0; ++} ++ ++/****************************************************************************** ++ * IRQ ++ *****************************************************************************/ ++static struct dcb_entry * ++lookup_dcb(struct drm_device *dev, int id, u32 mc) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int type, or, i; ++ ++ if (id < 4) { ++ type = OUTPUT_ANALOG; ++ or = id; ++ } else { ++ switch (mc & 0x00000f00) { ++ case 0x00000000: type = OUTPUT_LVDS; break; ++ case 0x00000100: type = OUTPUT_TMDS; break; ++ case 0x00000200: type = OUTPUT_TMDS; break; ++ case 0x00000500: type = OUTPUT_TMDS; break; ++ default: ++ NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc); ++ return NULL; ++ } ++ ++ or = id - 4; ++ } ++ ++ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { ++ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; ++ if (dcb->type == type && (dcb->or & (1 << or))) ++ return dcb; ++ } ++ ++ NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc); ++ return NULL; ++} ++ ++static void ++nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ int i; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); ++ if (!(mcc & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcc); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ u32 or, tmp, pclk; ++ int i; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); ++ if (!(mcc & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcc); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); ++ } ++ ++ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; ++ if (mask & 0x00010000) { ++ nv50_crtc_set_clock(dev, crtc, pclk); ++ } ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); ++ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); ++ if (!(mcp & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcp); ++ if (!dcb) ++ continue; ++ or = ffs(dcb->or) - 1; ++ ++ nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc); ++ ++ nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000); ++ switch (dcb->type) { ++ case OUTPUT_ANALOG: ++ nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000); ++ break; ++ case OUTPUT_TMDS: ++ case OUTPUT_LVDS: ++ if (cfg & 0x00000100) ++ tmp = 0x00000101; ++ else ++ tmp = 0x00000000; ++ ++ nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ int pclk, i; ++ ++ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); ++ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); ++ if (!(mcp & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcp); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc); ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_bh(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 mask, crtc; ++ int i; ++ ++ if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) { ++ NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset); ++ NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n", ++ nv_rd32(dev, 0x6101d0), ++ nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); ++ for (i = 0; i < 8; i++) { ++ NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n", ++ i < 4 ? "DAC" : "SOR", i, ++ nv_rd32(dev, 0x640180 + (i * 0x20)), ++ nv_rd32(dev, 0x660180 + (i * 0x20))); ++ } ++ } ++ ++ mask = nv_rd32(dev, 0x6101d4); ++ crtc = 0; ++ if (!mask) { ++ mask = nv_rd32(dev, 0x6109d4); ++ crtc = 1; ++ } ++ ++ if (disp->modeset & 0x00000001) ++ nvd0_display_unk1_handler(dev, crtc, mask); ++ if (disp->modeset & 0x00000002) ++ nvd0_display_unk2_handler(dev, crtc, mask); ++ if (disp->modeset & 0x00000004) ++ nvd0_display_unk4_handler(dev, crtc, mask); ++} ++ ++static void ++nvd0_display_intr(struct drm_device *dev) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 intr = nv_rd32(dev, 0x610088); ++ ++ if (intr & 0x00000002) { ++ u32 stat = nv_rd32(dev, 0x61009c); ++ int chid = ffs(stat) - 1; ++ if (chid >= 0) { ++ u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12)); ++ u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12)); ++ u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12)); ++ ++ NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x " ++ "0x%08x 0x%08x\n", ++ chid, (mthd & 0x0000ffc), data, mthd, unkn); ++ nv_wr32(dev, 0x61009c, (1 << chid)); ++ nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000); ++ } ++ ++ intr &= ~0x00000002; ++ } ++ ++ if (intr & 0x00100000) { ++ u32 stat = nv_rd32(dev, 0x6100ac); ++ ++ if (stat & 0x00000007) { ++ disp->modeset = stat; ++ tasklet_schedule(&disp->tasklet); ++ ++ nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); ++ stat &= ~0x00000007; ++ } ++ ++ if (stat) { ++ NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat); ++ nv_wr32(dev, 0x6100ac, stat); ++ } ++ ++ intr &= ~0x00100000; ++ } ++ ++ if (intr & 0x01000000) { ++ u32 stat = nv_rd32(dev, 0x6100bc); ++ nv_wr32(dev, 0x6100bc, stat); ++ intr &= ~0x01000000; ++ } ++ ++ if (intr & 0x02000000) { ++ u32 stat = nv_rd32(dev, 0x6108bc); ++ nv_wr32(dev, 0x6108bc, stat); ++ intr &= ~0x02000000; ++ } ++ ++ if (intr) ++ NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr); ++} ++ ++/****************************************************************************** ++ * Init ++ *****************************************************************************/ ++static void ++nvd0_display_fini(struct drm_device *dev) ++{ ++ int i; ++ ++ /* fini cursors */ ++ for (i = 14; i >= 13; i--) { ++ if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001)) ++ continue; ++ ++ nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000); ++ nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000); ++ nv_mask(dev, 0x610090, 1 << i, 0x00000000); ++ nv_mask(dev, 0x6100a0, 1 << i, 0x00000000); ++ } ++ ++ /* fini master */ ++ if (nv_rd32(dev, 0x610490) & 0x00000010) { ++ nv_mask(dev, 0x610490, 0x00000010, 0x00000000); ++ nv_mask(dev, 0x610490, 0x00000003, 0x00000000); ++ nv_wait(dev, 0x610490, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x610090, 0x00000001, 0x00000000); ++ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000); ++ } ++} ++ ++int ++nvd0_display_init(struct drm_device *dev) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 *push; ++ int i; ++ ++ if (nv_rd32(dev, 0x6100ac) & 0x00000100) { ++ nv_wr32(dev, 0x6100ac, 0x00000100); ++ nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) { ++ NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n", ++ nv_rd32(dev, 0x6194e8)); ++ return -EBUSY; ++ } ++ } ++ ++ /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't ++ * work at all unless you do the SOR part below. ++ */ ++ for (i = 0; i < 3; i++) { ++ u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800)); ++ nv_wr32(dev, 0x6101c0 + (i * 0x800), dac); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800)); ++ nv_wr32(dev, 0x6301c4 + (i * 0x800), sor); ++ } ++ ++ for (i = 0; i < 2; i++) { ++ u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800)); ++ u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800)); ++ u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800)); ++ nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0); ++ nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1); ++ nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2); ++ } ++ ++ /* point at our hash table / objects, enable interrupts */ ++ nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9); ++ nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307); ++ ++ /* init master */ ++ nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3); ++ nv_wr32(dev, 0x610498, 0x00010000); ++ nv_wr32(dev, 0x61049c, 0x00000001); ++ nv_mask(dev, 0x610490, 0x00000010, 0x00000010); ++ nv_wr32(dev, 0x640000, 0x00000000); ++ nv_wr32(dev, 0x610490, 0x01000013); ++ if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) { ++ NV_ERROR(dev, "PDISP: master 0x%08x\n", ++ nv_rd32(dev, 0x610490)); ++ return -EBUSY; ++ } ++ nv_mask(dev, 0x610090, 0x00000001, 0x00000001); ++ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001); ++ ++ /* init cursors */ ++ for (i = 13; i <= 14; i++) { ++ nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001); ++ if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) { ++ NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i, ++ nv_rd32(dev, 0x610490 + (i * 0x10))); ++ return -EBUSY; ++ } ++ ++ nv_mask(dev, 0x610090, 1 << i, 1 << i); ++ nv_mask(dev, 0x6100a0, 1 << i, 1 << i); ++ } ++ ++ push = evo_wait(dev, 0, 32); ++ if (!push) ++ return -EBUSY; ++ evo_mthd(push, 0x0088, 1); ++ evo_data(push, NvEvoSync); ++ evo_mthd(push, 0x0084, 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0084, 1); ++ evo_data(push, 0x80000000); ++ evo_mthd(push, 0x008c, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ ++ return 0; ++} ++ ++void ++nvd0_display_destroy(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvd0_display *disp = nvd0_display(dev); ++ struct pci_dev *pdev = dev->pdev; ++ ++ nvd0_display_fini(dev); ++ ++ pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle); ++ nouveau_gpuobj_ref(NULL, &disp->mem); ++ nouveau_irq_unregister(dev, 26); ++ ++ dev_priv->engine.display.priv = NULL; ++ kfree(disp); ++} ++ ++int ++nvd0_display_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; ++ struct dcb_table *dcb = &dev_priv->vbios.dcb; ++ struct drm_connector *connector, *tmp; ++ struct pci_dev *pdev = dev->pdev; ++ struct nvd0_display *disp; ++ struct dcb_entry *dcbe; ++ int ret, i; ++ ++ disp = kzalloc(sizeof(*disp), GFP_KERNEL); ++ if (!disp) ++ return -ENOMEM; ++ dev_priv->engine.display.priv = disp; ++ ++ /* create crtc objects to represent the hw heads */ ++ for (i = 0; i < 2; i++) { ++ ret = nvd0_crtc_create(dev, i); ++ if (ret) ++ goto out; ++ } ++ ++ /* create encoder/connector objects based on VBIOS DCB table */ ++ for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { ++ connector = nouveau_connector_create(dev, dcbe->connector); ++ if (IS_ERR(connector)) ++ continue; ++ ++ if (dcbe->location != DCB_LOC_ON_CHIP) { ++ NV_WARN(dev, "skipping off-chip encoder %d/%d\n", ++ dcbe->type, ffs(dcbe->or) - 1); ++ continue; ++ } ++ ++ switch (dcbe->type) { ++ case OUTPUT_TMDS: ++ case OUTPUT_LVDS: ++ nvd0_sor_create(connector, dcbe); ++ break; ++ case OUTPUT_ANALOG: ++ nvd0_dac_create(connector, dcbe); ++ break; ++ default: ++ NV_WARN(dev, "skipping unsupported encoder %d/%d\n", ++ dcbe->type, ffs(dcbe->or) - 1); ++ continue; ++ } ++ } ++ ++ /* cull any connectors we created that don't have an encoder */ ++ list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { ++ if (connector->encoder_ids[0]) ++ continue; ++ ++ NV_WARN(dev, "%s has no encoders, removing\n", ++ drm_get_connector_name(connector)); ++ connector->funcs->destroy(connector); ++ } ++ ++ /* setup interrupt handling */ ++ tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); ++ nouveau_irq_register(dev, 26, nvd0_display_intr); ++ ++ /* hash table and dma objects for the memory areas we care about */ ++ ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000, ++ NVOBJ_FLAG_ZERO_ALLOC, &disp->mem); ++ if (ret) ++ goto out; ++ ++ nv_wo32(disp->mem, 0x1000, 0x00000049); ++ nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8); ++ nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8); ++ nv_wo32(disp->mem, 0x100c, 0x00000000); ++ nv_wo32(disp->mem, 0x1010, 0x00000000); ++ nv_wo32(disp->mem, 0x1014, 0x00000000); ++ nv_wo32(disp->mem, 0x0000, NvEvoSync); ++ nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1020, 0x00000049); ++ nv_wo32(disp->mem, 0x1024, 0x00000000); ++ nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x102c, 0x00000000); ++ nv_wo32(disp->mem, 0x1030, 0x00000000); ++ nv_wo32(disp->mem, 0x1034, 0x00000000); ++ nv_wo32(disp->mem, 0x0008, NvEvoVRAM); ++ nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1040, 0x00000009); ++ nv_wo32(disp->mem, 0x1044, 0x00000000); ++ nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x104c, 0x00000000); ++ nv_wo32(disp->mem, 0x1050, 0x00000000); ++ nv_wo32(disp->mem, 0x1054, 0x00000000); ++ nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP); ++ nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1060, 0x0fe00009); ++ nv_wo32(disp->mem, 0x1064, 0x00000000); ++ nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x106c, 0x00000000); ++ nv_wo32(disp->mem, 0x1070, 0x00000000); ++ nv_wo32(disp->mem, 0x1074, 0x00000000); ++ nv_wo32(disp->mem, 0x0018, NvEvoFB32); ++ nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001); ++ ++ pinstmem->flush(dev); ++ ++ /* push buffers for evo channels */ ++ disp->evo[0].ptr = ++ pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle); ++ if (!disp->evo[0].ptr) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = nvd0_display_init(dev); ++ if (ret) ++ goto out; ++ ++out: ++ if (ret) ++ nvd0_display_destroy(dev); ++ return ret; ++} diff --git a/efi-dont-map-boot-services-on-32bit.patch b/efi-dont-map-boot-services-on-32bit.patch new file mode 100644 index 000000000..7cc614992 --- /dev/null +++ b/efi-dont-map-boot-services-on-32bit.patch @@ -0,0 +1,22 @@ +diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c +index 3ae4128..ff7dc70 100644 +--- a/arch/x86/platform/efi/efi.c ++++ b/arch/x86/platform/efi/efi.c +@@ -659,10 +659,13 @@ void __init efi_enter_virtual_mode(void) + + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + md = p; +- if (!(md->attribute & EFI_MEMORY_RUNTIME) && +- md->type != EFI_BOOT_SERVICES_CODE && +- md->type != EFI_BOOT_SERVICES_DATA) +- continue; ++ if (!(md->attribute & EFI_MEMORY_RUNTIME)) { ++#ifdef CONFIG_X86_64 ++ if (md->type != EFI_BOOT_SERVICES_CODE && ++ md->type != EFI_BOOT_SERVICES_DATA) ++#endif ++ continue; ++ } + + size = md->num_pages << EFI_PAGE_SHIFT; + end = md->phys_addr + size; diff --git a/exec-do-not-leave-bprm-interp-on-stack.patch b/exec-do-not-leave-bprm-interp-on-stack.patch new file mode 100644 index 000000000..2a4b2dd28 --- /dev/null +++ b/exec-do-not-leave-bprm-interp-on-stack.patch @@ -0,0 +1,118 @@ +From 20ae2081584450e552735a3df968ce5b5946a607 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Mon, 26 Nov 2012 08:56:37 -0500 +Subject: [PATCH 1/2] exec: do not leave bprm->interp on stack + +If a series of scripts are executed, each triggering module loading via +unprintable bytes in the script header, kernel stack contents can leak +into the command line. + +Normally execution of binfmt_script and binfmt_misc happens recursively. +However, when modules are enabled, and unprintable bytes exist in the +bprm->buf, execution will restart after attempting to load matching binfmt +modules. Unfortunately, the logic in binfmt_script and binfmt_misc does +not expect to get restarted. They leave bprm->interp pointing to their +local stack. This means on restart bprm->interp is left pointing into +unused stack memory which can then be copied into the userspace argv +areas. + +After additional study, it seems that both recursion and restart remains +the desirable way to handle exec with scripts, misc, and modules. As +such, we need to protect the changes to interp. + +This changes the logic to require allocation for any changes to the +bprm->interp. To avoid adding a new kmalloc to every exec, the default +value is left as-is. Only when passing through binfmt_script or +binfmt_misc does an allocation take place. + +For a proof of concept, see DoTest.sh from: +http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/ + +Signed-off-by: Kees Cook +Cc: halfdog +Cc: P J P +Cc: Alexander Viro +Cc: +Signed-off-by: Andrew Morton +--- + fs/binfmt_misc.c | 5 ++++- + fs/binfmt_script.c | 4 +++- + fs/exec.c | 15 +++++++++++++++ + include/linux/binfmts.h | 1 + + 4 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c +index 790b3cd..772428d 100644 +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -176,7 +176,10 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) + goto _error; + bprm->argc ++; + +- bprm->interp = iname; /* for binfmt_script */ ++ /* Update interp in case binfmt_script needs it. */ ++ retval = bprm_change_interp(iname, bprm); ++ if (retval < 0) ++ goto _error; + + interp_file = open_exec (iname); + retval = PTR_ERR (interp_file); +diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c +index d3b8c1f..df49d48 100644 +--- a/fs/binfmt_script.c ++++ b/fs/binfmt_script.c +@@ -82,7 +82,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) + retval = copy_strings_kernel(1, &i_name, bprm); + if (retval) return retval; + bprm->argc++; +- bprm->interp = interp; ++ retval = bprm_change_interp(interp, bprm); ++ if (retval < 0) ++ return retval; + + /* + * OK, now restart the process with the interpreter's dentry. +diff --git a/fs/exec.c b/fs/exec.c +index fab2c6d..59896ae 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1202,9 +1202,24 @@ void free_bprm(struct linux_binprm *bprm) + mutex_unlock(¤t->signal->cred_guard_mutex); + abort_creds(bprm->cred); + } ++ /* If a binfmt changed the interp, free it. */ ++ if (bprm->interp != bprm->filename) ++ kfree(bprm->interp); + kfree(bprm); + } + ++int bprm_change_interp(char *interp, struct linux_binprm *bprm) ++{ ++ /* If a binfmt changed the interp, free it first. */ ++ if (bprm->interp != bprm->filename) ++ kfree(bprm->interp); ++ bprm->interp = kstrdup(interp, GFP_KERNEL); ++ if (!bprm->interp) ++ return -ENOMEM; ++ return 0; ++} ++EXPORT_SYMBOL(bprm_change_interp); ++ + /* + * install the new credentials for this executable + */ +diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h +index 366422b..eb53e15 100644 +--- a/include/linux/binfmts.h ++++ b/include/linux/binfmts.h +@@ -128,6 +128,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm, + unsigned long stack_top, + int executable_stack); + extern int bprm_mm_init(struct linux_binprm *bprm); ++extern int bprm_change_interp(char *interp, struct linux_binprm *bprm); + extern int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm); + extern int prepare_bprm_creds(struct linux_binprm *bprm); +-- +1.8.0 + diff --git a/exec-use-eloop-for-max-recursion-depth.patch b/exec-use-eloop-for-max-recursion-depth.patch new file mode 100644 index 000000000..cbaff2f7a --- /dev/null +++ b/exec-use-eloop-for-max-recursion-depth.patch @@ -0,0 +1,144 @@ +From 4ae8186cd77835b45f1b35edb4ce70309287bfc3 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Mon, 26 Nov 2012 09:02:11 -0500 +Subject: [PATCH 2/2] exec: use -ELOOP for max recursion depth + +To avoid an explosion of request_module calls on a chain of abusive +scripts, fail maximum recursion with -ELOOP instead of -ENOEXEC. As soon +as maximum recursion depth is hit, the error will fail all the way back +up the chain, aborting immediately. + +This also has the side-effect of stopping the user's shell from attempting +to reexecute the top-level file as a shell script. As seen in the +dash source: + + if (cmd != path_bshell && errno == ENOEXEC) { + *argv-- = cmd; + *argv = cmd = path_bshell; + goto repeat; + } + +The above logic was designed for running scripts automatically that lacked +the "#!" header, not to re-try failed recursion. On a legitimate -ENOEXEC, +things continue to behave as the shell expects. + +Additionally, when tracking recursion, the binfmt handlers should not be +involved. The recursion being tracked is the depth of calls through +search_binary_handler(), so that function should be exclusively responsible +for tracking the depth. + +Signed-off-by: Kees Cook +Cc: halfdog +Cc: P J P +Cc: Alexander Viro +Signed-off-by: Andrew Morton +--- + fs/binfmt_em86.c | 1 - + fs/binfmt_misc.c | 6 ------ + fs/binfmt_script.c | 4 +--- + fs/exec.c | 10 +++++----- + include/linux/binfmts.h | 2 -- + 5 files changed, 6 insertions(+), 17 deletions(-) + +diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c +index 2790c7e..575796a 100644 +--- a/fs/binfmt_em86.c ++++ b/fs/binfmt_em86.c +@@ -42,7 +42,6 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) + return -ENOEXEC; + } + +- bprm->recursion_depth++; /* Well, the bang-shell is implicit... */ + allow_write_access(bprm->file); + fput(bprm->file); + bprm->file = NULL; +diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c +index 772428d..f0f1a06 100644 +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -117,10 +117,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) + if (!enabled) + goto _ret; + +- retval = -ENOEXEC; +- if (bprm->recursion_depth > BINPRM_MAX_RECURSION) +- goto _ret; +- + /* to keep locking time low, we copy the interpreter string */ + read_lock(&entries_lock); + fmt = check_file(bprm); +@@ -200,8 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) + if (retval < 0) + goto _error; + +- bprm->recursion_depth++; +- + retval = search_binary_handler (bprm, regs); + if (retval < 0) + goto _error; +diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c +index df49d48..8ae4be1 100644 +--- a/fs/binfmt_script.c ++++ b/fs/binfmt_script.c +@@ -22,15 +22,13 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) + char interp[BINPRM_BUF_SIZE]; + int retval; + +- if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || +- (bprm->recursion_depth > BINPRM_MAX_RECURSION)) ++ if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) + return -ENOEXEC; + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + +- bprm->recursion_depth++; + allow_write_access(bprm->file); + fput(bprm->file); + bprm->file = NULL; +diff --git a/fs/exec.c b/fs/exec.c +index 59896ae..541cc51 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1398,6 +1398,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) + struct linux_binfmt *fmt; + pid_t old_pid, old_vpid; + ++ /* This allows 4 levels of binfmt rewrites before failing hard. */ ++ if (depth > 5) ++ return -ELOOP; ++ + retval = security_bprm_check(bprm); + if (retval) + return retval; +@@ -1422,12 +1426,8 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) + if (!try_module_get(fmt->module)) + continue; + read_unlock(&binfmt_lock); ++ bprm->recursion_depth = depth + 1; + retval = fn(bprm, regs); +- /* +- * Restore the depth counter to its starting value +- * in this call, so we don't have to rely on every +- * load_binary function to restore it on return. +- */ + bprm->recursion_depth = depth; + if (retval >= 0) { + if (depth == 0) { +diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h +index eb53e15..5bab59b 100644 +--- a/include/linux/binfmts.h ++++ b/include/linux/binfmts.h +@@ -68,8 +68,6 @@ struct linux_binprm { + #define BINPRM_FLAGS_EXECFD_BIT 1 + #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT) + +-#define BINPRM_MAX_RECURSION 4 +- + /* Function parameter for binfmt->coredump */ + struct coredump_params { + long signr; +-- +1.8.0 + diff --git a/ext4-set-bg_itable_unused-when-resizing.patch b/ext4-set-bg_itable_unused-when-resizing.patch new file mode 100644 index 000000000..bd7bc4424 --- /dev/null +++ b/ext4-set-bg_itable_unused-when-resizing.patch @@ -0,0 +1,26 @@ +commit 93f9052643409c13b3b5f76833865087351f55b8 +Author: Theodore Ts'o +Date: Wed Sep 12 14:32:42 2012 -0400 + + ext4: set bg_itable_unused when resizing + + Set bg_itable_unused for file systems that have uninit_bg enabled. + This will speed up the first e2fsck run after the file system is + resized. + + Signed-off-by: "Theodore Ts'o" + +diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c +index 7adc088..a5be589 100644 +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -1268,6 +1268,9 @@ static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, + ext4_free_group_clusters_set(sb, gdp, + EXT4_B2C(sbi, group_data->free_blocks_count)); + ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); ++ if (ext4_has_group_desc_csum(sb)) ++ ext4_itable_unused_set(sb, gdp, ++ EXT4_INODES_PER_GROUP(sb)); + gdp->bg_flags = cpu_to_le16(*bg_flags); + ext4_group_desc_csum_set(sb, group, gdp); + diff --git a/fix-stack-memory-content-leak-via-UNAME26.patch b/fix-stack-memory-content-leak-via-UNAME26.patch new file mode 100644 index 000000000..5121ca06b --- /dev/null +++ b/fix-stack-memory-content-leak-via-UNAME26.patch @@ -0,0 +1,98 @@ +From 2702b1526c7278c4d65d78de209a465d4de2885e Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Fri, 19 Oct 2012 13:56:51 -0700 +Subject: [PATCH 1/2] kernel/sys.c: fix stack memory content leak via UNAME26 + +Calling uname() with the UNAME26 personality set allows a leak of kernel +stack contents. This fixes it by defensively calculating the length of +copy_to_user() call, making the len argument unsigned, and initializing +the stack buffer to zero (now technically unneeded, but hey, overkill). + +CVE-2012-0957 + +Reported-by: PaX Team +Signed-off-by: Kees Cook +Cc: Andi Kleen +Cc: PaX Team +Cc: Brad Spengler +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + kernel/sys.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/sys.c b/kernel/sys.c +index c5cb5b9..01865c6 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1265,15 +1265,16 @@ DECLARE_RWSEM(uts_sem); + * Work around broken programs that cannot handle "Linux 3.0". + * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 + */ +-static int override_release(char __user *release, int len) ++static int override_release(char __user *release, size_t len) + { + int ret = 0; +- char buf[65]; + + if (current->personality & UNAME26) { +- char *rest = UTS_RELEASE; ++ const char *rest = UTS_RELEASE; ++ char buf[65] = { 0 }; + int ndots = 0; + unsigned v; ++ size_t copy; + + while (*rest) { + if (*rest == '.' && ++ndots >= 3) +@@ -1283,8 +1284,9 @@ static int override_release(char __user *release, int len) + rest++; + } + v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; +- snprintf(buf, len, "2.6.%u%s", v, rest); +- ret = copy_to_user(release, buf, len); ++ copy = min(sizeof(buf), max_t(size_t, 1, len)); ++ copy = scnprintf(buf, copy, "2.6.%u%s", v, rest); ++ ret = copy_to_user(release, buf, copy + 1); + } + return ret; + } +-- +1.7.12.1 + + +From 31fd84b95eb211d5db460a1dda85e004800a7b52 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Fri, 19 Oct 2012 18:45:53 -0700 +Subject: [PATCH 2/2] use clamp_t in UNAME26 fix + +The min/max call needed to have explicit types on some architectures +(e.g. mn10300). Use clamp_t instead to avoid the warning: + + kernel/sys.c: In function 'override_release': + kernel/sys.c:1287:10: warning: comparison of distinct pointer types lacks a cast [enabled by default] + +Reported-by: Fengguang Wu +Signed-off-by: Kees Cook +Signed-off-by: Linus Torvalds +--- + kernel/sys.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sys.c b/kernel/sys.c +index 01865c6..e6e0ece 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1284,7 +1284,7 @@ static int override_release(char __user *release, size_t len) + rest++; + } + v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; +- copy = min(sizeof(buf), max_t(size_t, 1, len)); ++ copy = clamp_t(size_t, len, 1, sizeof(buf)); + copy = scnprintf(buf, copy, "2.6.%u%s", v, rest); + ret = copy_to_user(release, buf, copy + 1); + } +-- +1.7.12.1 + diff --git a/fix_xen_guest_on_old_EC2.patch b/fix_xen_guest_on_old_EC2.patch deleted file mode 100644 index e86200295..000000000 --- a/fix_xen_guest_on_old_EC2.patch +++ /dev/null @@ -1,34 +0,0 @@ - -Legacy hypervisors (RHEL 5.0 and RHEL 5.1) do not handle guest writes to -cr4 gracefully. If a guest attempts to write a bit of cr4 that is -unsupported, then the HV is so offended it crashes the domain. While -later guest kernels (such as RHEL6) don't assume the HV supports all -features, they do expect nicer responses. That assumption introduced -code that probes whether or not xsave is supported early in the boot. So -now when attempting to boot a RHEL6 guest on RHEL5.0 or RHEL5.1 an early -crash will occur. - -This patch is quite obviously an undesirable hack. The real fix for this -problem should be in the HV, and is, in later HVs. However, to support -running on old HVs, RHEL6 can take this small change. No impact will -occur for running on any RHEL HV (not even RHEL 5.5 supports xsave). -There is only potential for guest performance loss on upstream Xen. - ---- - arch/x86/xen/enlighten.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c -index 52f8e19..6db3d67 100644 ---- a/arch/x86/xen/enlighten.c -+++ b/arch/x86/xen/enlighten.c -@@ -802,6 +802,7 @@ static void xen_write_cr4(unsigned long cr4) - { - cr4 &= ~X86_CR4_PGE; - cr4 &= ~X86_CR4_PSE; -+ cr4 &= ~X86_CR4_OSXSAVE; - - native_write_cr4(cr4); - } --- -1.6.6.1 diff --git a/fs-lock-splice_read-and-splice_write-functions.patch b/fs-lock-splice_read-and-splice_write-functions.patch new file mode 100644 index 000000000..938cbd9f5 --- /dev/null +++ b/fs-lock-splice_read-and-splice_write-functions.patch @@ -0,0 +1,74 @@ +Lock splice_read and splice_write functions + +commit 1a25b1c4ce189e3926f2981f3302352a930086db +Author: Mikulas Patocka +Date: Mon Oct 15 17:20:17 2012 -0400 + + Lock splice_read and splice_write functions + + Functions generic_file_splice_read and generic_file_splice_write access + the pagecache directly. For block devices these functions must be locked + so that block size is not changed while they are in progress. + + This patch is an additional fix for commit b87570f5d349 ("Fix a crash + when block device is read and block size is changed at the same time") + that locked aio_read, aio_write and mmap against block size change. + + Signed-off-by: Mikulas Patocka + Signed-off-by: Linus Torvalds + +Index: linux-3.6.x86_64/fs/block_dev.c +=================================================================== +--- linux-3.6.x86_64.orig/fs/block_dev.c 2012-11-16 17:12:57.352936580 -0500 ++++ linux-3.6.x86_64/fs/block_dev.c 2012-11-16 17:13:11.908887989 -0500 +@@ -1662,6 +1662,39 @@ + return ret; + } + ++static ssize_t blkdev_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t ret; ++ struct block_device *bdev = I_BDEV(file->f_mapping->host); ++ ++ percpu_down_read(&bdev->bd_block_size_semaphore); ++ ++ ret = generic_file_splice_read(file, ppos, pipe, len, flags); ++ ++ percpu_up_read(&bdev->bd_block_size_semaphore); ++ ++ return ret; ++} ++ ++static ssize_t blkdev_splice_write(struct pipe_inode_info *pipe, ++ struct file *file, loff_t *ppos, size_t len, ++ unsigned int flags) ++{ ++ ssize_t ret; ++ struct block_device *bdev = I_BDEV(file->f_mapping->host); ++ ++ percpu_down_read(&bdev->bd_block_size_semaphore); ++ ++ ret = generic_file_splice_write(pipe, file, ppos, len, flags); ++ ++ percpu_up_read(&bdev->bd_block_size_semaphore); ++ ++ return ret; ++} ++ ++ + /* + * Try to release a page associated with block device when the system + * is under memory pressure. +@@ -1700,8 +1733,8 @@ + #ifdef CONFIG_COMPAT + .compat_ioctl = compat_blkdev_ioctl, + #endif +- .splice_read = generic_file_splice_read, +- .splice_write = generic_file_splice_write, ++ .splice_read = blkdev_splice_read, ++ .splice_write = blkdev_splice_write, + }; + + int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) diff --git a/hibernate-freeze-filesystems.patch b/hibernate-freeze-filesystems.patch new file mode 100644 index 000000000..841cab643 --- /dev/null +++ b/hibernate-freeze-filesystems.patch @@ -0,0 +1,287 @@ +commit b94887bbc0621e1e8402e7f0ec4bc3adf46c9a6e +Author: Rafael J. Wysocki +Date: Fri Feb 17 12:42:08 2012 -0500 + + Freeze all filesystems during system suspend and (kernel-driven) + hibernation by calling freeze_supers() for all superblocks and thaw + them during the subsequent resume with the help of thaw_supers(). + + This makes filesystems stay in a consistent state in case something + goes wrong between system suspend (or hibernation) and the subsequent + resume (e.g. journal replays won't be necessary in those cases). In + particular, this should help to solve a long-standing issue that, in + some cases, during resume from hibernation the boot loader causes the + journal to be replied for the filesystem containing the kernel image + and/or initrd causing it to become inconsistent with the information + stored in the hibernation image. + + The user-space-driven hibernation (s2disk) is not covered by this + change, because the freezing of filesystems prevents s2disk from + accessing device special files it needs to do its job. + + This change is based on earlier work by Nigel Cunningham. + + Signed-off-by: Rafael J. Wysocki + + Rebased to 3.3-rc3 by Josh Boyer + +diff --git a/fs/super.c b/fs/super.c +index 6015c02..c8057fa 100644 +--- a/fs/super.c ++++ b/fs/super.c +@@ -594,6 +594,79 @@ void iterate_supers_type(struct file_system_type *type, + EXPORT_SYMBOL(iterate_supers_type); + + /** ++ * thaw_supers - call thaw_super() for all superblocks ++ */ ++void thaw_supers(void) ++{ ++ struct super_block *sb, *p = NULL; ++ ++ spin_lock(&sb_lock); ++ list_for_each_entry(sb, &super_blocks, s_list) { ++ if (hlist_unhashed(&sb->s_instances)) ++ continue; ++ sb->s_count++; ++ spin_unlock(&sb_lock); ++ ++ if (sb->s_flags & MS_FROZEN) { ++ thaw_super(sb); ++ sb->s_flags &= ~MS_FROZEN; ++ } ++ ++ spin_lock(&sb_lock); ++ if (p) ++ __put_super(p); ++ p = sb; ++ } ++ if (p) ++ __put_super(p); ++ spin_unlock(&sb_lock); ++} ++ ++/** ++ * freeze_supers - call freeze_super() for all superblocks ++ */ ++int freeze_supers(void) ++{ ++ struct super_block *sb, *p = NULL; ++ int error = 0; ++ ++ spin_lock(&sb_lock); ++ /* ++ * Freeze in reverse order so filesystems depending on others are ++ * frozen in the right order (eg. loopback on ext3). ++ */ ++ list_for_each_entry_reverse(sb, &super_blocks, s_list) { ++ if (hlist_unhashed(&sb->s_instances)) ++ continue; ++ sb->s_count++; ++ spin_unlock(&sb_lock); ++ ++ if (sb->s_root && sb->s_frozen != SB_FREEZE_TRANS ++ && !(sb->s_flags & MS_RDONLY)) { ++ error = freeze_super(sb); ++ if (!error) ++ sb->s_flags |= MS_FROZEN; ++ } ++ ++ spin_lock(&sb_lock); ++ if (error) ++ break; ++ if (p) ++ __put_super(p); ++ p = sb; ++ } ++ if (p) ++ __put_super(p); ++ spin_unlock(&sb_lock); ++ ++ if (error) ++ thaw_supers(); ++ ++ return error; ++} ++ ++ ++/** + * get_super - get the superblock of a device + * @bdev: device to get the superblock for + * +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 386da09..a164f4a 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -210,6 +210,7 @@ struct inodes_stat_t { + #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ + #define MS_I_VERSION (1<<23) /* Update inode I_version field */ + #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ ++#define MS_FROZEN (1<<25) /* Frozen filesystem */ + #define MS_NOSEC (1<<28) + #define MS_BORN (1<<29) + #define MS_ACTIVE (1<<30) +@@ -2501,6 +2502,8 @@ extern void drop_super(struct super_block *sb); + extern void iterate_supers(void (*)(struct super_block *, void *), void *); + extern void iterate_supers_type(struct file_system_type *, + void (*)(struct super_block *, void *), void *); ++extern int freeze_supers(void); ++extern void thaw_supers(void); + + extern int dcache_dir_open(struct inode *, struct file *); + extern int dcache_dir_close(struct inode *, struct file *); +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 6d6d288..492fc62 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -626,12 +626,17 @@ int hibernate(void) + if (error) + goto Finish; + +- error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ error = freeze_supers(); + if (error) + goto Thaw; ++ ++ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ if (error) ++ goto Thaw_fs; ++ + if (freezer_test_done) { + freezer_test_done = false; +- goto Thaw; ++ goto Thaw_fs; + } + + if (in_suspend) { +@@ -655,6 +660,8 @@ int hibernate(void) + pr_debug("PM: Image restored successfully.\n"); + } + ++ Thaw_fs: ++ thaw_supers(); + Thaw: + thaw_processes(); + Finish: +diff --git a/kernel/power/power.h b/kernel/power/power.h +index 21724ee..40d6f64 100644 +--- a/kernel/power/power.h ++++ b/kernel/power/power.h +@@ -1,3 +1,4 @@ ++#include + #include + #include + #include +@@ -227,45 +228,3 @@ enum { + #define TEST_MAX (__TEST_AFTER_LAST - 1) + + extern int pm_test_level; +- +-#ifdef CONFIG_SUSPEND_FREEZER +-static inline int suspend_freeze_processes(void) +-{ +- int error; +- +- error = freeze_processes(); +- +- /* +- * freeze_processes() automatically thaws every task if freezing +- * fails. So we need not do anything extra upon error. +- */ +- if (error) +- goto Finish; +- +- error = freeze_kernel_threads(); +- +- /* +- * freeze_kernel_threads() thaws only kernel threads upon freezing +- * failure. So we have to thaw the userspace tasks ourselves. +- */ +- if (error) +- thaw_processes(); +- +- Finish: +- return error; +-} +- +-static inline void suspend_thaw_processes(void) +-{ +- thaw_processes(); +-} +-#else +-static inline int suspend_freeze_processes(void) +-{ +- return 0; +-} +- +-static inline void suspend_thaw_processes(void) +-{ +-} +-#endif +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 4fd51be..5f51fc7 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -29,6 +29,62 @@ + + #include "power.h" + ++#ifdef CONFIG_SUSPEND_FREEZER ++ ++static inline int suspend_freeze_processes(void) ++{ ++ int error; ++ ++ error = freeze_processes(); ++ ++ /* ++ * freeze_processes() automatically thaws every task if freezing ++ * fails. So we need not do anything extra upon error. ++ */ ++ ++ if (error) ++ goto Finish; ++ ++ error = freeze_supers(); ++ if (error) { ++ thaw_processes(); ++ goto Finish; ++ } ++ ++ error = freeze_kernel_threads(); ++ ++ /* ++ * freeze_kernel_threads() thaws only kernel threads upon freezing ++ * failure. So we have to thaw the userspace tasks ourselves. ++ */ ++ if (error) { ++ thaw_supers(); ++ thaw_processes(); ++ } ++ ++Finish: ++ return error; ++} ++ ++static inline void suspend_thaw_processes(void) ++{ ++ thaw_supers(); ++ thaw_processes(); ++} ++ ++#else /* !CONFIG_SUSPEND_FREEZER */ ++ ++static inline int suspend_freeze_processes(void) ++{ ++ return 0; ++} ++ ++static inline void suspend_thaw_processes(void) ++{ ++} ++ ++#endif /* !CONFIG_SUSPEND_FREEZER */ ++ + const char *const pm_states[PM_SUSPEND_MAX] = { + [PM_SUSPEND_STANDBY] = "standby", + [PM_SUSPEND_MEM] = "mem", diff --git a/ips-noirq.patch b/ips-noirq.patch new file mode 100644 index 000000000..95837ecf4 --- /dev/null +++ b/ips-noirq.patch @@ -0,0 +1,15 @@ +--- a/drivers/platform/x86/intel_ips.c ++++ a/drivers/platform/x86/intel_ips.c +@@ -1603,6 +1603,12 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) + goto error_unmap; + } + ++ /* No IRQ assigned is a BIOS failure... */ ++ if (dev->irq <= 0) { ++ ret = -ENODEV; ++ goto error_unmap; ++ } ++ + /* + * IRQ handler for ME interaction + * Note: don't use MSI here as the PCH has bugs. diff --git a/iwlegacy-fix-IBSS-cleanup.patch b/iwlegacy-fix-IBSS-cleanup.patch new file mode 100644 index 000000000..5533aed75 --- /dev/null +++ b/iwlegacy-fix-IBSS-cleanup.patch @@ -0,0 +1,104 @@ +From 658f1bd2dd632209df00ec66349e15941ffdd83b Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Wed, 16 Jan 2013 10:28:09 +0000 +Subject: [PATCH 3.8] iwlegacy: fix IBSS cleanup + +We do not correctly change interface type when switching from +IBSS mode to STA mode, that results in microcode errors. + +Resolves: +https://bugzilla.redhat.com/show_bug.cgi?id=886946 + +Reported-by: Jaroslav Skarvada +Cc: stable@vger.kernel.org +Signed-off-by: Stanislaw Gruszka +--- + drivers/net/wireless/iwlegacy/common.c | 35 ++++++++++++++-------------------- + 1 file changed, 14 insertions(+), 21 deletions(-) + +diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c +index 7e16d10..90b8970 100644 +--- a/drivers/net/wireless/iwlegacy/common.c ++++ b/drivers/net/wireless/iwlegacy/common.c +@@ -3958,17 +3958,21 @@ il_connection_init_rx_config(struct il_priv *il) + + memset(&il->staging, 0, sizeof(il->staging)); + +- if (!il->vif) { ++ switch (il->iw_mode) { ++ case NL80211_IFTYPE_UNSPECIFIED: + il->staging.dev_type = RXON_DEV_TYPE_ESS; +- } else if (il->vif->type == NL80211_IFTYPE_STATION) { ++ break; ++ case NL80211_IFTYPE_STATION: + il->staging.dev_type = RXON_DEV_TYPE_ESS; + il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; +- } else if (il->vif->type == NL80211_IFTYPE_ADHOC) { ++ break; ++ case NL80211_IFTYPE_ADHOC: + il->staging.dev_type = RXON_DEV_TYPE_IBSS; + il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + il->staging.filter_flags = + RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; +- } else { ++ break; ++ default: + IL_ERR("Unsupported interface type %d\n", il->vif->type); + return; + } +@@ -4550,8 +4554,7 @@ out: + EXPORT_SYMBOL(il_mac_add_interface); + + static void +-il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, +- bool mode_change) ++il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif) + { + lockdep_assert_held(&il->mutex); + +@@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, + il_force_scan_end(il); + } + +- if (!mode_change) +- il_set_mode(il); +- ++ il_set_mode(il); + } + + void +@@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + + WARN_ON(il->vif != vif); + il->vif = NULL; +- +- il_teardown_interface(il, vif, false); ++ il->iw_mode = NL80211_IFTYPE_UNSPECIFIED; ++ il_teardown_interface(il, vif); + memset(il->bssid, 0, ETH_ALEN); + + D_MAC80211("leave\n"); +@@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + } + + /* success */ +- il_teardown_interface(il, vif, true); + vif->type = newtype; + vif->p2p = false; +- err = il_set_mode(il); +- WARN_ON(err); +- /* +- * We've switched internally, but submitting to the +- * device may have failed for some reason. Mask this +- * error, because otherwise mac80211 will not switch +- * (and set the interface type back) and we'll be +- * out of sync with it. +- */ ++ il->iw_mode = newtype; ++ il_teardown_interface(il, vif); + err = 0; + + out: +-- +1.8.0.2 + diff --git a/kernel.spec b/kernel.spec index d13d02707..fe5ef7877 100644 --- a/kernel.spec +++ b/kernel.spec @@ -6,7 +6,7 @@ Summary: The Linux kernel # For a stable, released kernel, released_kernel should be 1. For rawhide # and/or a kernel built from an rc or git snapshot, released_kernel should # be 0. -%global released_kernel 0 +%global released_kernel 1 # Save original buildid for later if it's defined %if 0%{?buildid:1} @@ -48,27 +48,30 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -# For non-released -rc kernels, this will be prepended with "0.", so -# for example a 3 here will become 0.3 +# NOTE: baserelease must be > 0 or bad things will happen if you switch +# to a released kernel (released version will be < rc version) # -%global baserelease 1 +# For non-released -rc kernels, this will be appended after the rcX and +# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" +# +%global baserelease 7 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching # on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base, # which yields a base_sublevel of 21. -%define base_sublevel 0 +%define base_sublevel 6 ## If this is a released kernel ## %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 0 +%define stable_update 11 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly %if 0%{?stable_update} -%define stablerev .%{stable_update} +%define stablerev %{stable_update} %define stable_base %{stable_update} %if 0%{?stable_rc} # stable RCs are incremental patches, so we need the previous stable patch @@ -84,7 +87,7 @@ Summary: The Linux kernel # The rc snapshot level %define rcrev 0 # The git snapshot level -%define gitrev 3 +%define gitrev 0 # Set rpm version accordingly %define rpmversion 3.%{upstream_sublevel}.0 %endif @@ -113,8 +116,8 @@ Summary: The Linux kernel %define with_headers %{?_without_headers: 0} %{?!_without_headers: 1} # kernel-firmware %define with_firmware %{?_with_firmware: 1} %{?!_with_firmware: 0} -# tools/perf -%define with_perf %{?_without_perf: 0} %{?!_without_perf: 1} +# tools +%define with_tools %{?_without_tools: 0} %{?!_without_tools: 1} # kernel-debuginfo %define with_debuginfo %{?_without_debuginfo: 0} %{?!_without_debuginfo: 1} # kernel-bootwrapper (for creating zImages from kernel + initrd) @@ -130,7 +133,7 @@ Summary: The Linux kernel %define doc_build_fail true %endif -%define rawhide_skip_docs 1 +%define rawhide_skip_docs 0 %if 0%{?rawhide_skip_docs} %define with_doc 0 %define doc_build_fail true @@ -153,7 +156,7 @@ Summary: The Linux kernel # Set debugbuildsenabled to 1 for production (build separate debug kernels) # and 0 for rawhide (all kernels are debug kernels). # See also 'make debug' and 'make release'. -%define debugbuildsenabled 0 +%define debugbuildsenabled 1 # Want to build a vanilla kernel build without any non-upstream patches? %define with_vanilla %{?_with_vanilla: 1} %{?!_with_vanilla: 0} @@ -163,8 +166,10 @@ Summary: The Linux kernel %if 0%{?stable_rc} %define stable_rctag .rc%{stable_rc} +%define pkg_release 0%{stable_rctag}.%{fedora_build}%{?buildid}%{?dist} +%else +%define pkg_release %{fedora_build}%{?buildid}%{?dist} %endif -%define pkg_release %{fedora_build}%{?stable_rctag}%{?buildid}%{?dist} %else @@ -258,7 +263,7 @@ Summary: The Linux kernel %endif %define with_smp 0 %define with_pae 0 -%define with_perf 0 +%define with_tools 0 %endif %define all_x86 i386 i686 @@ -289,7 +294,7 @@ Summary: The Linux kernel %ifarch noarch %define with_up 0 %define with_headers 0 -%define with_perf 0 +%define with_tools 0 %define all_arch_configs kernel-%{version}-*.config %define with_firmware %{?_with_firmware: 1} %{?!_with_firmware: 0} %endif @@ -338,16 +343,16 @@ Summary: The Linux kernel %define image_install_path boot %define make_target image %define kernel_image arch/s390/boot/image -%define with_perf 0 +%define with_tools 0 %endif %ifarch sparc64 %define asmarch sparc %define all_arch_configs kernel-%{version}-sparc64*.config -%define make_target image -%define kernel_image arch/sparc/boot/image +%define make_target vmlinux +%define kernel_image vmlinux %define image_install_path boot -%define with_perf 0 +%define with_tools 0 %endif %ifarch sparcv9 @@ -364,13 +369,6 @@ Summary: The Linux kernel %define kernel_image_elf 1 %endif -%ifarch ia64 -%define all_arch_configs kernel-%{version}-ia64*.config -%define image_install_path boot/efi/EFI/redhat -%define make_target compressed -%define kernel_image vmlinux.gz -%endif - %ifarch alpha alphaev56 %define all_arch_configs kernel-%{version}-alpha*.config %define image_install_path boot @@ -378,14 +376,6 @@ Summary: The Linux kernel %define kernel_image vmlinux %endif -%ifarch %{arm} -%define all_arch_configs kernel-%{version}-arm*.config -%define image_install_path boot -%define hdrarch arm -%define make_target vmlinux -%define kernel_image vmlinux -%endif - %if %{nopatches} # XXX temporary until last vdso patches are upstream %define vdso_arches ppc ppc64 @@ -406,14 +396,14 @@ Summary: The Linux kernel # Which is a BadThing(tm). # We only build kernel-headers on the following... -%define nobuildarches i386 s390 sparc sparcv9 %{arm} +%define nobuildarches i386 s390 sparc sparcv9 %ifarch %nobuildarches %define with_up 0 %define with_smp 0 %define with_pae 0 %define with_debuginfo 0 -%define with_perf 0 +%define with_tools 0 %define _enable_debug_packages 0 %endif @@ -422,6 +412,9 @@ Summary: The Linux kernel %define with_pae_debug %{with_debug} %endif +# Architectures we build tools/cpupower on +%define cpupowerarchs %{ix86} x86_64 ppc ppc64 + # # Three sets of minimum package version requirements in the form of Conflicts: # to versions below the minimum @@ -431,7 +424,7 @@ Summary: The Linux kernel # First the general kernel 2.6 required versions as per # Documentation/Changes # -%define kernel_dot_org_conflicts ppp < 2.4.3-3, isdn4k-utils < 3.2-32, nfs-utils < 1.0.7-12, e2fsprogs < 1.37-4, util-linux < 2.12, jfsutils < 1.1.7-2, reiserfs-utils < 3.6.19-2, xfsprogs < 2.6.13-4, procps < 3.2.5-6.3, oprofile < 0.9.1-2, module-init-tools < 3.13-1, device-mapper-libs < 1.02.63-2, mdadm < 3.2.1-5 +%define kernel_dot_org_conflicts ppp < 2.4.3-3, isdn4k-utils < 3.2-32, nfs-utils < 1.0.7-12, e2fsprogs < 1.37-4, util-linux < 2.12, jfsutils < 1.1.7-2, reiserfs-utils < 3.6.19-2, xfsprogs < 2.6.13-4, procps < 3.2.5-6.3, oprofile < 0.9.1-2, device-mapper-libs < 1.02.63-2, mdadm < 3.2.1-5 # # Then a series of requirements that are distribution specific, either @@ -449,7 +442,7 @@ Summary: The Linux kernel # Packages that need to be installed before the kernel is, because the %%post # scripts use them. # -%define kernel_prereq fileutils, module-init-tools, initscripts >= 8.11.1-1, grubby >= 7.0.10-1 +%define kernel_prereq fileutils, module-init-tools >= 3.16-5, initscripts >= 8.11.1-1, grubby >= 8.3-1 %define initrd_prereq dracut >= 001-7 # @@ -470,7 +463,7 @@ Requires(pre): %{initrd_prereq}\ %if %{with_firmware}\ Requires(pre): kernel-firmware >= %{rpmversion}-%{pkg_release}\ %else\ -Requires(pre): linux-firmware >= 20100806-2\ +Requires(pre): linux-firmware >= 20120206-0.1.git06c8f81\ %endif\ Requires(post): /sbin/new-kernel-pkg\ Requires(preun): /sbin/new-kernel-pkg\ @@ -494,7 +487,7 @@ Version: %{rpmversion} Release: %{pkg_release} # DO NOT CHANGE THE 'ExclusiveArch' LINE TO TEMPORARILY EXCLUDE AN ARCHITECTURE BUILD. # SET %%nobuildarches (ABOVE) INSTEAD -ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 ia64 %{sparc} s390 s390x alpha alphaev56 %{arm} +ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 %{sparc} s390 s390x alpha alphaev56 ExclusiveOS: Linux %kernel_reqprovconf @@ -503,15 +496,15 @@ ExclusiveOS: Linux # List the packages used during the kernel build # BuildRequires: module-init-tools, patch >= 2.5.4, bash >= 2.03, sh-utils, tar -BuildRequires: bzip2, findutils, gzip, m4, perl, make >= 3.78, diffutils, gawk -BuildRequires: gcc >= 3.4.2, binutils >= 2.12, redhat-rpm-config +BuildRequires: bzip2, xz, findutils, gzip, m4, perl, make >= 3.78, diffutils, gawk +BuildRequires: gcc >= 3.4.2, binutils >= 2.12, redhat-rpm-config, hmaccalc BuildRequires: net-tools BuildRequires: xmlto, asciidoc %if %{with_sparse} BuildRequires: sparse >= 0.4.1 %endif -%if %{with_perf} -BuildRequires: elfutils-devel zlib-devel binutils-devel newt-devel python-devel perl(ExtUtils::Embed) +%if %{with_tools} +BuildRequires: elfutils-devel zlib-devel binutils-devel newt-devel python-devel perl(ExtUtils::Embed) pciutils-devel gettext bison %endif BuildConflicts: rhbuildsys(DiskFree) < 500Mb @@ -528,7 +521,7 @@ BuildRequires: rpm-build >= 4.4.2.1-4 %define debuginfo_args --strict-build-id %endif -Source0: ftp://ftp.kernel.org/pub/linux/kernel/v3.0/linux-%{kversion}.tar.bz2 +Source0: ftp://ftp.kernel.org/pub/linux/kernel/v3.0/linux-%{kversion}.tar.xz Source11: genkey Source14: find-provides @@ -542,6 +535,7 @@ Source24: config-rhel-generic Source30: config-x86-generic Source31: config-i686-PAE +Source32: config-x86-32-generic Source40: config-x86_64-generic @@ -550,28 +544,28 @@ Source51: config-powerpc32-generic Source52: config-powerpc32-smp Source53: config-powerpc64 -Source60: config-ia64-generic - Source70: config-s390x Source90: config-sparc64-generic -Source100: config-arm - # This file is intentionally left empty in the stock kernel. Its a nicety # added for those wanting to do custom rebuilds with altered config opts. Source1000: config-local +# Sources for kernel-tools +Source2000: cpupower.service +Source2001: cpupower.config + # Here should be only the patches up to the upstream canonical Linus tree. # For a stable release kernel %if 0%{?stable_update} %if 0%{?stable_base} -%define stable_patch_00 patch-3.%{base_sublevel}.%{stable_base}.bz2 +%define stable_patch_00 patch-3.%{base_sublevel}.%{stable_base}.xz Patch00: %{stable_patch_00} %endif %if 0%{?stable_rc} -%define stable_patch_01 patch-3.%{base_sublevel}.%{stable_update}-rc%{stable_rc}.bz2 +%define stable_patch_01 patch-3.%{base_sublevel}.%{stable_update}-rc%{stable_rc}.xz Patch01: %{stable_patch_01} %endif @@ -580,9 +574,9 @@ Patch01: %{stable_patch_01} # near the top of this spec file. %else %if 0%{?rcrev} -Patch00: patch-3.%{upstream_sublevel}-rc%{rcrev}.bz2 +Patch00: patch-3.%{upstream_sublevel}-rc%{rcrev}.xz %if 0%{?gitrev} -Patch01: patch-3.%{upstream_sublevel}-rc%{rcrev}-git%{gitrev}.bz2 +Patch01: patch-3.%{upstream_sublevel}-rc%{rcrev}-git%{gitrev}.xz %endif %else # pre-{base_sublevel+1}-rc1 case @@ -613,20 +607,15 @@ Patch09: linux-2.6-upstream-reverts.patch # Standalone patches -Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch - +Patch100: taint-vbox.patch Patch160: linux-2.6-32bit-mmap-exec-randomization.patch Patch161: linux-2.6-i386-nx-emulation.patch - -Patch202: linux-2.6-debug-taint-vm.patch -Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch - -Patch383: linux-2.6-defaults-aspm.patch +Patch162: nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch Patch390: linux-2.6-defaults-acpi-video.patch Patch391: linux-2.6-acpi-video-dos.patch -Patch393: acpi-ec-add-delay-before-write.patch Patch394: linux-2.6-acpi-debug-infinite-loop.patch +Patch396: acpi-sony-nonvs-blacklist.patch Patch450: linux-2.6-input-kill-stupid-messages.patch Patch452: linux-2.6.30-no-pcspkr-modalias.patch @@ -636,7 +625,9 @@ Patch460: linux-2.6-serial-460800.patch Patch470: die-floppy-die.patch Patch510: linux-2.6-silence-noise.patch +Patch520: quite-apm.patch Patch530: linux-2.6-silence-fbcon-logo.patch +Patch540: silence-empty-ipi-mask-warning.patch Patch700: linux-2.6-e1000-ich9-montevina.patch @@ -645,16 +636,13 @@ Patch800: linux-2.6-crash-driver.patch # crypto/ # virt + ksm patches -Patch1555: fix_xen_guest_on_old_EC2.patch # DRM +#atch1700: drm-edid-try-harder-to-fix-up-broken-headers.patch -# nouveau + drm fixes -Patch1810: drm-nouveau-updates.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch -# make sure the lvds comes back on lid open -Patch1825: drm-intel-make-lvds-work.patch +Patch1825: drm-i915-dp-stfu.patch Patch1900: linux-2.6-intel-iommu-igfx.patch @@ -663,30 +651,107 @@ Patch1900: linux-2.6-intel-iommu-igfx.patch Patch2802: linux-2.6-silence-acpi-blacklist.patch # media patches -Patch2899: linux-2.6-v4l-dvb-fixes.patch -Patch2900: linux-2.6-v4l-dvb-update.patch -Patch2901: linux-2.6-v4l-dvb-experimental.patch -Patch2902: linux-2.6-v4l-dvb-uvcvideo-update.patch +Patch2901: drivers-media-update.patch # fs fixes # NFSv4 # patches headed upstream -Patch12010: add-appleir-usb-driver.patch Patch12016: disable-i8042-check-on-apple-mac.patch -Patch12018: neuter_intel_microcode_load.patch - -# Runtime power management -Patch12203: linux-2.6-usb-pci-autosuspend.patch -Patch12204: linux-2.6-enable-more-pci-autosuspend.patch -Patch12205: runtime_pm_fixups.patch - Patch12303: dmar-disable-when-ricoh-multifunction.patch -Patch20000: utrace.patch +Patch13003: efi-dont-map-boot-services-on-32bit.patch + +Patch14010: lis3-improve-handling-of-null-rate.patch + +Patch19000: ips-noirq.patch + +#rhbz 769766 +Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch + +Patch21226: pci-crs-blacklist.patch + +#rhbz 754518 +#Patch21235: scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch + +#rhbz 804957 CVE-2012-1568 +Patch21306: shlib_base_randomize.patch + +#rhbz 869904 869909 CVE-2012-4508 +Patch22080: 0001-ext4-ext4_inode_info-diet.patch +Patch22081: 0002-ext4-give-i_aiodio_unwritten-a-more-appropriate-name.patch +Patch22082: 0003-ext4-fix-unwritten-counter-leakage.patch +Patch22083: 0004-ext4-completed_io-locking-cleanup.patch +Patch22084: 0005-ext4-serialize-dio-nonlocked-reads-with-defrag-worke.patch +Patch22085: 0006-ext4-serialize-unlocked-dio-reads-with-truncate.patch +Patch22086: 0007-ext4-endless-truncate-due-to-nonlocked-dio-readers.patch +Patch22087: 0008-ext4-serialize-truncate-with-owerwrite-DIO-workers.patch +Patch22088: 0009-ext4-punch_hole-should-wait-for-DIO-writers.patch +Patch22089: 0010-ext4-fix-ext_remove_space-for-punch_hole-case.patch +Patch22090: 0011-ext4-fix-ext4_flush_completed_IO-wait-semantics.patch +Patch22091: 0012-ext4-serialize-fallocate-with-ext4_convert_unwritten.patch + +# Debug patches +Patch30000: weird-root-dentry-name-debug.patch +Patch30010: debug-808990.patch + +#rhbz 871078 +Patch22112: USB-report-submission-of-active-URBs.patch + +#rhbz 869341 +Patch22113: smp_irq_move_cleanup_interrupt.patch + +#rhbz 812129 +Patch22120: block-fix-a-crash-when-block-device-is.patch +Patch22121: blockdev-turn-a-rw-semaphore-into-a-percpu-rw-sem.patch +Patch22122: fs-lock-splice_read-and-splice_write-functions.patch + +#rhbz 874791 +Patch22125: Bluetooth-Add-support-for-BCM20702A0.patch + +#rhbz CVE-2012-4530 868285 880147 +Patch21228: exec-do-not-leave-bprm-interp-on-stack.patch +Patch21229: exec-use-eloop-for-max-recursion-depth.patch + +#rhbz 869629 +Patch21230: SCSI-mvsas-Fix-oops-when-ata-commond-timeout.patch + +#rhbz 851278 +Patch21231: 8139cp-revert-set-ring-address-before-enabling-receiver.patch +Patch21232: 8139cp-set-ring-address-after-enabling-C-mode.patch +Patch21233: 8139cp-re-enable-interrupts-after-tx-timeout.patch + +#rhbz 883414 +Patch21234: mac80211-fix-ibss-scanning.patch + +#rhbz 873107 +Patch21237: 0001-ACPI-sony-laptop-do-proper-memcpy-for-ACPI_TYPE_INTE.patch + +#rhbz 874372 +Patch21238: don-t-do-blind-d_drop-in-nfs_prime_dcache.patch + +#rhbz 853064 +Patch21239: aoe-remove-extra-bdi_init.patch + +#rhbz 890547 +Patch21240: ACPI-do-not-use-Lid-and-Sleep-button-for-S5-wakeup.patch + +#rhbz 886946 +Patch21241: iwlegacy-fix-IBSS-cleanup.patch + +#rhbz 852833 +Patch21245: ext4-set-bg_itable_unused-when-resizing.patch + +#rhbz 896051 896038 CVE-2013-0190 +Patch21250: xen-fix-stack-corruption-in-xen_failsafe_callback.patch + +#rhbz 908693 908706 +Patch21251: x86-msr-Add-capabilities-check.patch + +# END OF PATCH DEFINITIONS %endif @@ -751,27 +816,59 @@ Group: Development/Debug This package is required by %{name}-debuginfo subpackages. It provides the kernel source files common to all builds. -%if %{with_perf} -%package -n perf -Summary: Performance monitoring for the Linux kernel +%if %{with_tools} +%package -n kernel-tools +Summary: Assortment of tools for the Linux kernel Group: Development/System License: GPLv2 -%description -n perf -This package provides the perf tool and the supporting documentation. +Obsoletes: perf < 3.1.0-0.rc2.git7.2 +Provides: perf = %{version}-%{release} +Provides: cpupowerutils = 1:009-0.6.p1 +Obsoletes: cpupowerutils < 1:009-0.6.p1 +Provides: cpufreq-utils = 1:009-0.6.p1 +Provides: cpufrequtils = 1:009-0.6.p1 +Obsoletes: cpufreq-utils < 1:009-0.6.p1 +Obsoletes: cpufrequtils < 1:009-0.6.p1 +Obsoletes: cpuspeed < 1:1.5-16 +Requires: kernel-tools-libs = %{version}-%{release} +%description -n kernel-tools +This package contains the tools/ directory from the kernel source +- the perf tool and the supporting documentation. -%package -n perf-debuginfo -Summary: Debug information for package perf +%package -n kernel-tools-libs +Summary: Libraries for the kernels-tools +Group: Development/System +License: GPLv2 +%description -n kernel-tools-libs +This package contains the libraries built from the tools/ directory +from the kernel source. + +%package -n kernel-tools-libs-devel +Summary: Assortment of tools for the Linux kernel +Group: Development/System +License: GPLv2 +Requires: kernel-tools = %{version}-%{release} +Provides: cpupowerutils-devel = 1:009-0.6.p1 +Obsoletes: cpupowerutils-devel < 1:009-0.6.p1 +Requires: kernel-tools-libs = %{version}-%{release} +Provides: kernel-tools-devel +%description -n kernel-tools-libs-devel +This package contains the development files for the tools/ directory from +the kernel source. + +%package -n kernel-tools-debuginfo +Summary: Debug information for package kernel-tools Group: Development/Debug Requires: %{name}-debuginfo-common-%{_target_cpu} = %{version}-%{release} AutoReqProv: no -%description -n perf-debuginfo -This package provides debug information for package perf. +%description -n kernel-tools-debuginfo +This package provides debug information for package kernel-tools. # Note that this pattern only works right to match the .build-id # symlinks because of the trailing nonmatching alternation and # the leading .*, because of find-debuginfo.sh's buggy handling # of matching the pattern against the symlinks file. -%{expand:%%global debuginfo_args %{?debuginfo_args} -p '.*%%{_bindir}/perf(\.debug)?|.*%%{_libexecdir}/perf-core/.*|XXX' -o perf-debuginfo.list} +%{expand:%%global debuginfo_args %{?debuginfo_args} -p '.*%%{_bindir}/perf(\.debug)?|.*%%{_libexecdir}/perf-core/.*|.*%%{_bindir}/centrino-decode(\.debug)?|.*%%{_bindir}/powernow-k8-decode(\.debug)?|.*%%{_bindir}/cpupower(\.debug)?|.*%%{_libdir}/libcpupower.*|XXX' -o kernel-tools-debuginfo.list} %endif @@ -896,6 +993,11 @@ exit 1 %endif %endif +%if "%{baserelease}" == "0" +echo "baserelease must be greater than zero" +exit 1 +%endif + # more sanity checking; do it quietly if [ "%{patches}" != "%%{patches}" ] ; then for patch in %{patches} ; do @@ -924,7 +1026,8 @@ ApplyPatch() %endif case "$patch" in *.bz2) bunzip2 < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; - *.gz) gunzip < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; + *.gz) gunzip < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; + *.xz) unxz < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; *) $patch_command ${1+"$@"} < "$RPM_SOURCE_DIR/$patch" ;; esac } @@ -1129,31 +1232,21 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R # Architecture patches # x86(-64) +ApplyPatch taint-vbox.patch # -# Intel IOMMU +# NX Emulation # +#ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch +#ApplyPatch linux-2.6-i386-nx-emulation.patch +#ApplyPatch nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch +#rhbz 804957 CVE-2012-1568 +#ApplyPatch shlib_base_randomize.patch -# -# PowerPC -# - -# -# SPARC64 -# -ApplyPatch linux-2.6.29-sparc-IOC_TYPECHECK.patch - -# -# Exec shield -# -ApplyPatch linux-2.6-i386-nx-emulation.patch -ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # # bugfixes to drivers and filesystems # -# ext4 - # xfs # btrfs @@ -1170,18 +1263,12 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # ACPI ApplyPatch linux-2.6-defaults-acpi-video.patch ApplyPatch linux-2.6-acpi-video-dos.patch -ApplyPatch acpi-ec-add-delay-before-write.patch ApplyPatch linux-2.6-acpi-debug-infinite-loop.patch - -# Various low-impact patches to aid debugging. -ApplyPatch linux-2.6-debug-taint-vm.patch -ApplyPatch linux-2.6-debug-vm-would-have-oomkilled.patch +ApplyPatch acpi-sony-nonvs-blacklist.patch # # PCI # -# enable ASPM by default on hardware we expect to work -ApplyPatch linux-2.6-defaults-aspm.patch # # SCSI Bits. @@ -1193,6 +1280,7 @@ ApplyPatch linux-2.6-defaults-aspm.patch # Networking + # Misc fixes # The input layer spews crap no-one cares about. ApplyPatch linux-2.6-input-kill-stupid-messages.patch @@ -1211,6 +1299,9 @@ ApplyPatch linux-2.6-silence-noise.patch # Make fbcon not show the penguins with 'quiet' ApplyPatch linux-2.6-silence-fbcon-logo.patch +# no-one cares about these warnings. +ApplyPatch silence-empty-ipi-mask-warning.patch + # Changes to upstream defaults. @@ -1223,46 +1314,112 @@ ApplyPatch linux-2.6-e1000-ich9-montevina.patch # crypto/ # Assorted Virt Fixes -ApplyPatch fix_xen_guest_on_old_EC2.patch # DRM core - -# Nouveau DRM -ApplyOptionalPatch drm-nouveau-updates.patch +#ApplyPatch drm-edid-try-harder-to-fix-up-broken-headers.patch # Intel DRM ApplyOptionalPatch drm-intel-next.patch -ApplyPatch drm-intel-make-lvds-work.patch +ApplyPatch drm-i915-dp-stfu.patch + ApplyPatch linux-2.6-intel-iommu-igfx.patch # silence the ACPI blacklist code ApplyPatch linux-2.6-silence-acpi-blacklist.patch +ApplyPatch quite-apm.patch -# V4L/DVB updates/fixes/experimental drivers +# Media (V4L/DVB/IR) updates/fixes/experimental drivers # apply if non-empty -ApplyOptionalPatch linux-2.6-v4l-dvb-fixes.patch -ApplyOptionalPatch linux-2.6-v4l-dvb-update.patch -ApplyOptionalPatch linux-2.6-v4l-dvb-experimental.patch -#ApplyPatch linux-2.6-v4l-dvb-uvcvideo-update.patch +ApplyOptionalPatch drivers-media-update.patch # Patches headed upstream + ApplyPatch disable-i8042-check-on-apple-mac.patch -ApplyPatch add-appleir-usb-driver.patch - -ApplyPatch neuter_intel_microcode_load.patch - -# Runtime PM -#ApplyPatch linux-2.6-usb-pci-autosuspend.patch -### Broken by implicit notify support & ACPICA rebase -###ApplyPatch linux-2.6-enable-more-pci-autosuspend.patch -#ApplyPatch runtime_pm_fixups.patch - # rhbz#605888 ApplyPatch dmar-disable-when-ricoh-multifunction.patch -# utrace. -#ApplyPatch utrace.patch +ApplyPatch efi-dont-map-boot-services-on-32bit.patch + +ApplyPatch lis3-improve-handling-of-null-rate.patch + +ApplyPatch ips-noirq.patch + +#ApplyPatch pci-crs-blacklist.patch + +#rhbz 754518 +#ApplyPatch scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch + +# debug patches +ApplyPatch weird-root-dentry-name-debug.patch +ApplyPatch debug-808990.patch + +#rhbz 869904 869909 CVE-2012-4508 +ApplyPatch 0001-ext4-ext4_inode_info-diet.patch +ApplyPatch 0002-ext4-give-i_aiodio_unwritten-a-more-appropriate-name.patch +ApplyPatch 0003-ext4-fix-unwritten-counter-leakage.patch +ApplyPatch 0004-ext4-completed_io-locking-cleanup.patch +ApplyPatch 0005-ext4-serialize-dio-nonlocked-reads-with-defrag-worke.patch +ApplyPatch 0006-ext4-serialize-unlocked-dio-reads-with-truncate.patch +ApplyPatch 0007-ext4-endless-truncate-due-to-nonlocked-dio-readers.patch +ApplyPatch 0008-ext4-serialize-truncate-with-owerwrite-DIO-workers.patch +ApplyPatch 0009-ext4-punch_hole-should-wait-for-DIO-writers.patch +ApplyPatch 0010-ext4-fix-ext_remove_space-for-punch_hole-case.patch +ApplyPatch 0011-ext4-fix-ext4_flush_completed_IO-wait-semantics.patch +ApplyPatch 0012-ext4-serialize-fallocate-with-ext4_convert_unwritten.patch + +#rhbz 871078 +ApplyPatch USB-report-submission-of-active-URBs.patch + +#rhbz 869341 +ApplyPatch smp_irq_move_cleanup_interrupt.patch + +#rhbz 812129 +ApplyPatch block-fix-a-crash-when-block-device-is.patch +ApplyPatch blockdev-turn-a-rw-semaphore-into-a-percpu-rw-sem.patch +ApplyPatch fs-lock-splice_read-and-splice_write-functions.patch + +#rhbz 874791 +ApplyPatch Bluetooth-Add-support-for-BCM20702A0.patch + +#rhbz CVE-2012-4530 868285 880147 +ApplyPatch exec-do-not-leave-bprm-interp-on-stack.patch +ApplyPatch exec-use-eloop-for-max-recursion-depth.patch + +#rhbz 869629 +ApplyPatch SCSI-mvsas-Fix-oops-when-ata-commond-timeout.patch + +#rhbz 851278 +ApplyPatch 8139cp-revert-set-ring-address-before-enabling-receiver.patch -R +ApplyPatch 8139cp-set-ring-address-after-enabling-C-mode.patch +ApplyPatch 8139cp-re-enable-interrupts-after-tx-timeout.patch + +#rhbz 883414 +ApplyPatch mac80211-fix-ibss-scanning.patch + +#rhbz 873107 +ApplyPatch 0001-ACPI-sony-laptop-do-proper-memcpy-for-ACPI_TYPE_INTE.patch + +#rhbz 874372 +ApplyPatch don-t-do-blind-d_drop-in-nfs_prime_dcache.patch + +#rhbz 853064 +ApplyPatch aoe-remove-extra-bdi_init.patch + +#rhbz 890547 +ApplyPatch ACPI-do-not-use-Lid-and-Sleep-button-for-S5-wakeup.patch + +#rhbz 886946 +ApplyPatch iwlegacy-fix-IBSS-cleanup.patch + +#rhbz 852833 +ApplyPatch ext4-set-bg_itable_unused-when-resizing.patch + +#rhbz 896051 896038 CVE-2013-0190 +ApplyPatch xen-fix-stack-corruption-in-xen_failsafe_callback.patch + +#rhbz 908693 908706 +ApplyPatch x86-msr-Add-capabilities-check.patch # END OF PATCH APPLICATIONS @@ -1272,6 +1429,7 @@ ApplyPatch dmar-disable-when-ricoh-multifunction.patch chmod +x scripts/checkpatch.pl +# This Prevents scripts/setlocalversion from mucking with our version numbers. touch .scmversion # only deal with configs if we are going to build for the arch @@ -1365,14 +1523,18 @@ BuildKernel() { KernelVer=%{version}-%{release}.%{_target_cpu}${Flavour:+.${Flavour}} echo BUILDING A KERNEL FOR ${Flavour} %{_target_cpu}... - # make sure EXTRAVERSION says what we want it to say - perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = %{?stablerev}-%{release}.%{_target_cpu}${Flavour:+.${Flavour}}/" Makefile + %if 0%{?stable_update} + # make sure SUBLEVEL is incremented on a stable release. Sigh 3.x. + perl -p -i -e "s/^SUBLEVEL.*/SUBLEVEL = %{?stablerev}/" Makefile + %endif - # if pre-rc1 devel kernel, must fix up SUBLEVEL for our versioning scheme - ### XXX this will probably be dead code in 3.0 --kyle + # make sure EXTRAVERSION says what we want it to say + perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = -%{release}.%{_target_cpu}${Flavour:+.${Flavour}}/" Makefile + + # if pre-rc1 devel kernel, must fix up PATCHLEVEL for our versioning scheme %if !0%{?rcrev} %if 0%{?gitrev} - perl -p -i -e 's/^SUBLEVEL.*/SUBLEVEL = %{upstream_sublevel}/' Makefile + perl -p -i -e 's/^PATCHLEVEL.*/PATCHLEVEL = %{upstream_sublevel}/' Makefile %endif %endif @@ -1408,6 +1570,11 @@ BuildKernel() { $RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer chmod 755 $RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer + # hmac sign the kernel for FIPS + echo "Creating hmac file: $RPM_BUILD_ROOT/%{image_install_path}/.vmlinuz-$KernelVer.hmac" + ls -l $RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer + sha512hmac $RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer | sed -e "s,$RPM_BUILD_ROOT,," > $RPM_BUILD_ROOT/%{image_install_path}/.vmlinuz-$KernelVer.hmac; + mkdir -p $RPM_BUILD_ROOT/lib/modules/$KernelVer # Override $(mod-fw) because we don't want it to install any firmware # We'll do that ourselves with 'make firmware_install' @@ -1436,6 +1603,7 @@ BuildKernel() { # dirs for additional modules per module-init-tools, kbuild/modules.txt mkdir -p $RPM_BUILD_ROOT/lib/modules/$KernelVer/extra mkdir -p $RPM_BUILD_ROOT/lib/modules/$KernelVer/updates + # first copy everything cp --parents `find -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build @@ -1457,7 +1625,7 @@ BuildKernel() { fi rm -f $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/scripts/*.o rm -f $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/scripts/*/*.o -%ifarch ppc +%ifarch ppc ppc64 cp -a --parents arch/powerpc/lib/crtsavres.[So] $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/ %endif if [ -d arch/%{asmarch}/include ]; then @@ -1506,7 +1674,7 @@ BuildKernel() { } collect_modules_list networking \ - 'register_netdev|ieee80211_register_hw|usbnet_probe|phy_driver_register' + 'register_netdev|ieee80211_register_hw|usbnet_probe|phy_driver_register|rt(l_|2x00)(pci|usb)_probe' collect_modules_list block \ 'ata_scsi_ioctl|scsi_add_host|scsi_add_host_with_dma|blk_init_queue|register_mtd_blktrans|scsi_esp_register|scsi_register_device_handler' collect_modules_list drm \ @@ -1537,10 +1705,16 @@ BuildKernel() { # Move the devel headers out of the root file system mkdir -p $RPM_BUILD_ROOT/usr/src/kernels mv $RPM_BUILD_ROOT/lib/modules/$KernelVer/build $RPM_BUILD_ROOT/$DevelDir - ln -sf ../../..$DevelDir $RPM_BUILD_ROOT/lib/modules/$KernelVer/build + + # This is going to create a broken link during the build, but we don't use + # it after this point. We need the link to actually point to something + # when kernel-devel is installed, and a relative link doesn't work across + # the F17 UsrMove feature. + ln -sf $DevelDir $RPM_BUILD_ROOT/lib/modules/$KernelVer/build # prune junk from kernel-devel find $RPM_BUILD_ROOT/usr/src/kernels -name ".*.cmd" -exec rm -f {} \; + } ### @@ -1574,11 +1748,27 @@ BuildKernel %make_target %kernel_image BuildKernel %make_target %kernel_image smp %endif -%global perf_make \ - make %{?_smp_mflags} -C tools/perf -s V=1 HAVE_CPLUS_DEMANGLE=1 prefix=%{_prefix} -%if %{with_perf} -%{perf_make} all -%{perf_make} man || %{doc_build_fail} +%if %{with_tools} +# perf +make %{?_smp_mflags} -C tools/perf -s V=1 HAVE_CPLUS_DEMANGLE=1 prefix=%{_prefix} all +make %{?_smp_mflags} -C tools/perf -s V=1 prefix=%{_prefix} man || %{doc_build_fail} + +%ifarch %{cpupowerarchs} +# cpupower +# make sure version-gen.sh is executable. +chmod +x tools/power/cpupower/utils/version-gen.sh +make %{?_smp_mflags} -C tools/power/cpupower CPUFREQ_BENCH=false +%ifarch %{ix86} + cd tools/power/cpupower/debug/i386 + make %{?_smp_mflags} centrino-decode powernow-k8-decode + cd - +%endif +%ifarch x86_64 + cd tools/power/cpupower/debug/x86_64 + make %{?_smp_mflags} centrino-decode powernow-k8-decode + cd - +%endif +%endif %endif %if %{with_doc} @@ -1625,7 +1815,7 @@ man9dir=$RPM_BUILD_ROOT%{_datadir}/man/man9 # copy the source over mkdir -p $docdir -tar -f - --exclude=man --exclude='.*' -c Documentation | tar xf - -C $docdir +tar -h -f - --exclude=man --exclude='.*' -c Documentation | tar xf - -C $docdir # Install man pages for the kernel API. mkdir -p $man9dir @@ -1634,13 +1824,9 @@ xargs -0 --no-run-if-empty %{__install} -m 444 -t $man9dir $m ls $man9dir | grep -q '' || > $man9dir/BROKEN %endif # with_doc -%if %{with_perf} -# perf tool binary and supporting scripts/binaries -%{perf_make} DESTDIR=$RPM_BUILD_ROOT install - -# perf man pages (note: implicit rpm magic compresses them later) -%{perf_make} DESTDIR=$RPM_BUILD_ROOT install-man || %{doc_build_fail} -%endif +# We have to do the headers install before the tools install because the +# kernel headers_install will remove any header files in /usr/include that +# it doesn't install itself. %if %{with_headers} # Install kernel headers @@ -1666,6 +1852,38 @@ rm -f $RPM_BUILD_ROOT/usr/include/asm*/io.h rm -f $RPM_BUILD_ROOT/usr/include/asm*/irq.h %endif +%if %{with_tools} +# perf tool binary and supporting scripts/binaries +make -C tools/perf -s V=1 DESTDIR=$RPM_BUILD_ROOT HAVE_CPLUS_DEMANGLE=1 prefix=%{_prefix} install + +# perf man pages (note: implicit rpm magic compresses them later) +make -C tools/perf -s V=1 DESTDIR=$RPM_BUILD_ROOT HAVE_CPLUS_DEMANGLE=1 prefix=%{_prefix} install-man || %{doc_build_fail} + +%ifarch %{cpupowerarchs} +make -C tools/power/cpupower DESTDIR=$RPM_BUILD_ROOT libdir=%{_libdir} mandir=%{_mandir} CPUFREQ_BENCH=false install +rm -f %{buildroot}%{_libdir}/*.{a,la} +%find_lang cpupower +mv cpupower.lang ../ +%ifarch %{ix86} + cd tools/power/cpupower/debug/i386 + install -m755 centrino-decode %{buildroot}%{_bindir}/centrino-decode + install -m755 powernow-k8-decode %{buildroot}%{_bindir}/powernow-k8-decode + cd - +%endif +%ifarch x86_64 + cd tools/power/cpupower/debug/x86_64 + install -m755 centrino-decode %{buildroot}%{_bindir}/centrino-decode + install -m755 powernow-k8-decode %{buildroot}%{_bindir}/powernow-k8-decode + cd - +%endif +chmod 0755 %{buildroot}%{_libdir}/libcpupower.so* +mkdir -p %{buildroot}%{_unitdir} %{buildroot}%{_sysconfdir}/sysconfig +install -m644 %{SOURCE2000} %{buildroot}%{_unitdir}/cpupower.service +install -m644 %{SOURCE2001} %{buildroot}%{_sysconfdir}/sysconfig/cpupower +%endif + +%endif + %if %{with_firmware} %{build_firmware} %endif @@ -1686,6 +1904,14 @@ rm -rf $RPM_BUILD_ROOT ### scripts ### +%if %{with_tools} +%post -n kernel-tools +/sbin/ldconfig + +%postun -n kernel-tools +/sbin/ldconfig +%endif + # # This macro defines a %%post script for a kernel*-devel package. # %%kernel_devel_post [] @@ -1705,6 +1931,7 @@ then\ fi\ %{nil} + # This macro defines a %%posttrans script for a kernel package. # %%kernel_variant_posttrans [] # More text can follow to go at the end of this variant's %%post. @@ -1797,18 +2024,38 @@ fi %{_datadir}/man/man9/* %endif -%if %{with_perf} -%files -n perf +%if %{with_tools} +%files -n kernel-tools -f cpupower.lang %defattr(-,root,root) %{_bindir}/perf %dir %{_libexecdir}/perf-core %{_libexecdir}/perf-core/* %{_mandir}/man[1-8]/* +%ifarch %{cpupowerarchs} +%{_bindir}/cpupower +%ifarch %{ix86} x86_64 +%{_bindir}/centrino-decode +%{_bindir}/powernow-k8-decode +%endif +%{_unitdir}/cpupower.service +%config(noreplace) %{_sysconfdir}/sysconfig/cpupower +%endif + %if %{with_debuginfo} -%files -f perf-debuginfo.list -n perf-debuginfo +%files -f kernel-tools-debuginfo.list -n kernel-tools-debuginfo %defattr(-,root,root) %endif + +%ifarch %{cpupowerarchs} +%files -n kernel-tools-libs +%{_libdir}/libcpupower.so.0 +%{_libdir}/libcpupower.so.0.0.0 + +%files -n kernel-tools-libs-devel +%{_libdir}/libcpupower.so +%{_includedir}/cpufreq.h +%endif %endif # This is %%{image_install_path} on an arch where that includes ELF files, @@ -1825,6 +2072,7 @@ fi %{expand:%%files %{?2}}\ %defattr(-,root,root)\ /%{image_install_path}/%{?-k:%{-k*}}%{!?-k:vmlinuz}-%{KVERREL}%{?2:.%{2}}\ +/%{image_install_path}/.vmlinuz-%{KVERREL}%{?2:.%{2}}.hmac \ %attr(600,root,root) /boot/System.map-%{KVERREL}%{?2:.%{2}}\ /boot/config-%{KVERREL}%{?2:.%{2}}\ %dir /lib/modules/%{KVERREL}%{?2:.%{2}}\ @@ -1873,10 +2121,1206 @@ fi # and build. %changelog -* Mon Jul 25 2011 Kyle McMartin -- Linux 3.0-git3 -- Drop hda_intel-prealloc-4mb-dmabuffer.patch, set new - CONFIG_SND_HDA_PREALLOC_SIZE=4096 for similar effect. +* Thu Feb 07 2013 Josh Boyer +- Fix local privilege escalation in MSR code (rhbz 908693 908706) + +* Wed Jan 23 2013 Dave Jones +- Remove warning about empty IPI mask. + +* Wed Jan 16 2013 Justin M. Forbes 3.6.11-6 +- Fix resize2fs issue with ext4 (rhbz 852833) +- Fix for CVE-2013-0190 xen corruption with 32bit pvops (rhbz 896051 896038) + +* Wed Jan 16 2013 Josh Boyer +- Add patch from Stanislaw Gruszka to fix iwlegacy IBSS cleanup (rhbz 886946) + +* Tue Jan 08 2013 Josh Boyer - 3.6.11-4 +- Add patch to fix shutdown on some machines (rhbz 890547) + +* Fri Jan 04 2013 Josh Boyer +- Fix oops on aoe module removal (rhbz 853064) + +* Wed Jan 02 2013 Josh Boyer +- Fix autofs issue in 3.6 (rhbz 874372) + +* Mon Dec 17 2012 Josh Boyer - 3.6.11-1 +- Linux v3.6.11 +- Fix oops in sony-laptop setup (rhbz 873107) + +* Tue Dec 11 2012 Josh Boyer +- Fix IBSS scanning in mac80211 (rhbz 883414) + +* Tue Dec 11 2012 Justin M. Forbes 3.6.10-1 +- Linux 3.6.10 + +* Mon Dec 03 2012 Josh Boyer - 3.6.9-2 +- Backport 3 upstream fixes to resolve radeon schedule IB errors (rhbz 855275) + +* Mon Dec 03 2012 Josh Boyer - 3.6.9-1 +- Linux v3.6.9 + +* Tue Nov 27 2012 Josh Boyer - 3.6.8-2 +- Update patches for 8139cp issues from David Woodhouse (rhbz 851278) + +* Mon Nov 26 2012 Josh Boyer - 3.6.8-1 +- Linux v3.6.8 + +* Mon Nov 26 2012 Josh Boyer - 3.6.7-6 +- Fix regression in 8139cp driver, debugged by William J. Eaton (rhbz 851278) +- Fix ACPI video after _DOD errors (rhbz 869383) +- Fix ata command timeout oops in mvsas (rhbz 869629) +- CVE-2012-4530: stack disclosure binfmt_script load_script (rhbz 868285 880147) + +* Tue Nov 20 2012 Josh Boyer +- CVE-2012-4461: kvm: invalid opcode oops on SET_SREGS with OSXSAVE bit set (rhbz 878518 862900) +- Add support for BCM20702A0 (rhbz 874791) + +* Mon Nov 19 2012 Josh Boyer +- Apply patches from Jeff Moyer to fix direct-io oops (rhbz 812129) + +* Sat Nov 17 2012 Justin M. Forbes - 3.6.7-1 +- linux 3.6.7 + +* Fri Nov 16 2012 Josh Boyer +- Fix oops causing typo in keyspan driver (rhbz 870562) +- Don't WARN_ON empty queues in iwlwifi (rhbz 873001) + +* Thu Nov 15 2012 Justin M. Forbes +- Fix panic in panic in smp_irq_move_cleanup_interrupt (rhbz 869341) + +* Mon Nov 12 2012 Justin M. Forbes +- fix list_del corruption warning on USB audio with twinkle (rhbz 871078) + +* Mon Nov 05 2012 Justin M. Forbes 3.6.6-1 +- Linux 3.6.6 + +* Thu Nov 01 2012 Justin M. Forbes 3.6.5-3 +- Drop unhandled irq patch. (rhbz 845211) + +* Wed Oct 30 2012 Justin M. Forbes 3.6.5-2 +- Fix i82975x_edac OOPS (BZ#848149) + +* Wed Oct 30 2012 Justin M. Forbes 3.6.5-1 +- Linux 3.6.5 + +* Wed Oct 30 2012 Josh Boyer +- CVE-2012-4565 net: divide by zero in tcp algorithm illinois (rhbz 871848 871923) + +* Mon Oct 29 2012 Justin M. Forbes 3.6.4-1 +- Linux 3.6.4 + +* Thu Oct 25 2012 Justin M. Forbes +- CVE-2012-4508: ext4: AIO vs fallocate stale data exposure (rhbz 869904 869909) + +* Wed Oct 24 2012 Josh Boyer +- Remove patch added for rhbz 856863 +- Add patch to fix corrupted text with i915 (rhbz 852210) + +* Mon Oct 22 2012 Josh Boyer +- Add patch to fix CIFS oops from Jeff Layton (rhbz 867344) +- CVE-2012-0957: uts: stack memory leak in UNAME26 (rhbz 862877 864824) +- Fix rt2x00 usb reset resume (rhbz 856863) + +* Thu Oct 18 2012 Josh Boyer +- Patch to have mac80211 connect with HT20 if HT40 is not allowed (rhbz 866013) +- Apply patch from Stanislaw Gruszka to fix mac80211 issue (rhbz 862168) +- Apply patch to fix iwlwifi crash (rhbz 770484) + +* Tue Oct 16 2012 Dave Jones 3.6.2-1 +- Linux 3.6.2 + +* Tue Oct 16 2012 Dave Jones 3.6.0-1 +- Linux 3.6 + +* Tue Oct 16 2012 Dave Jones 3.5.7-1 +- Linux 3.5.7 + +* Tue Oct 16 2012 Dave Jones 3.5.0-1 +- Linux 3.5 + +* Tue Oct 16 2012 Dave Jones 3.4.14-1 +- Linux 3.4.14 + +* Thu Oct 11 2012 Dave Jones 3.4.13-1 +- Linux 3.4.13 + +* Wed Oct 03 2012 Josh Boyer +- Make sure kernel-tools-libs-devel provides kernel-tools-devel + +* Tue Oct 02 2012 Dave Jones 3.4.12-1 +- Linux v3.4.12 + merged: drm-radeon-force-dma32-to-fix-regression-rs4xx-rs6xx.patch + merged: rds-set-correct-msg_namelen.patch + merged: net-Allow-driver-to-limit-number-of-GSO-segments-per-skb.patch + merged: sfc-Fix-maximum-number-of-TSO-segments-and-minimum-TX-queue-size.patch + merged: tcp-Apply-device-TSO-segment-limit-earlier.patch + merged: af_netlink-credentials-cve-2012-3520.patch + +* Fri Sep 28 2012 Josh Boyer - 3.4.11-3 +- Split out kernel-tools-libs (rhbz 859943) + +* Fri Sep 21 2012 Josh Boyer 3.4.11-2 +- Add patch to fix radeon regression from Jerome Glisse (rhbz 785375) + +* Sun Sep 16 2012 Josh Boyer 3.4.11-1 +- Linux v3.4.11 + +* Tue Sep 11 2012 Josh Boyer 3.4.10-2 +- Drop old Xen EC2 patch. It is no longer needed per Matt Wilson + +* Wed Sep 05 2012 Josh Boyer 3.4.10-1 +- Linux v3.4.10 + +* Thu Aug 23 2012 Justin M. Forbes 3.4.9-2 +- af_netlink: force credentials passing [CVE-2012-3520] +- Add patches from 3.4.10 queue + +* Wed Aug 15 2012 Justin M. Forbes 3.4.9-1 +- Linux 3.4.9 + +* Tue Aug 14 2012 Justin M. Forbes 3.4.8-1 +- Linux 3.4.8 + +* Fri Aug 03 2012 Josh Boyer +- CVE-2012-3412 sfc: potential rDOS through TCP MSS option (rhbz 844714 845558) + +* Mon Jul 30 2012 Dave Jones 3.4.7-1 +- Linux 3.4.7 + +* Thu Jul 26 2012 Josh Boyer +- kernel: recv{from,msg}() on an rds socket can leak kernel + memory (rhbz 820039 843554) +- Apply patch to fix uvcvideo crash (rhbz 836742) + +* Wed Jul 25 2012 Josh Boyer +- Drop ARM support. It isn't built in F16. +- Add patch to fix cpu pinning after suspend/resume (rhbz 714271) + +* Thu Jul 19 2012 Josh Boyer - 3.4.6-1 +- Linux v3.4.6 + +* Wed Jul 18 2012 Josh Boyer +- check return value of power_supply_register from Lan Tianyu (rhbz 772730) + +* Mon Jul 16 2012 Josh Boyer - 3.4.5-1 +- Linux v3.4.5 + +* Thu Jul 12 2012 Josh Boyer +- Add patch to fix ACPICA null pointer exception regression (rhbz 834318) + +* Wed Jul 11 2012 Justin M. Forbes +- Fix FIPS for aesni hardware (rhbz 839239) + +* Tue Jul 10 2012 Josh Boyer +- Add patch to fix xen dom0 crash when using BLKDISCARD (rhbz 824641) + +* Fri Jul 06 2012 Justin M. Forbes +- ACPI, APEI, Avoid too much error reporting in runtime + +* Thu Jul 05 2012 Josh Boyer +- Fix device misprobe for Gobi devices (rhbz 829880) +- Fix breakage in nouveau with nv_two_heads (rhbz 830359) +- Apply patch to fix tg3 watchdog hangs on BCM5906 devices (rhbz 825123) + +* Wed Jul 4 2012 Josh Boyer +- Patch from Stanislaw Gruszka to fix rt2x00 USB access point (rhbz 828824) + +* Tue Jul 3 2012 Josh Boyer +- Allow ACPI backlight to still work if _DOS isn't present (rhbz 834910) + +* Fri Jun 29 2012 John W. Linville +- ath9k: fix panic caused by returning a descriptor we have... (rhbz 832927) + +* Tue Jun 26 2012 Dave Jones 3.4.4-3 +- Add mm-correctly-synchronize-rss-counters-at-exit-exec.patch (rhbz 832867) + +* Tue Jun 26 2012 Josh Boyer +- Add task_work_add backport from Anton Arapov +- Add patch to fix mount hangs (rhbz 835019) + +* Tue Jun 26 2012 John W. Linville +- ath9k_htc: configure bssid on ASSOC/IBSS change (rhbz 828731) + +* Fri Jun 22 2012 Justin M. Forbes 3.4.4-1 +- Linux 3.4.4 + +* Fri Jun 22 2012 Josh Boyer +- Add uprobe backports from Anton Arapov (rhbz 832083) +- Disable UDL DRM driver per Dave Airlie + +* Wed Jun 20 2012 Josh Boyer +- Fix incorrect logic in irqpoll patch + +* Tue Jun 19 2012 Josh Boyer +- Add proposed patch to fix READ_CAPACITY command on usb keys (rhbz 831807) + +* Mon Jun 18 2012 Justin M. Forbes 3.4.3-1 +- Linux 3.4.3 + +* Mon Jun 18 2012 Josh Boyer +- Add patch to fix CIFS password mount option parsing (rhbz 832741) +- Add patch to fix udl device binding (rhbz 832188) + +* Thu Jun 14 2012 Justin M. Forbes 3.4.2-1 +- Linux 3.4.2 + +* Mon Jun 04 2012 Josh Boyer 3.3.8-1 +- Linux v3.3.8 + +* Mon Jun 04 2012 Dave Jones +- Disable 32bit NX emulation. + +* Wed May 30 2012 Josh Boyer +- CVE-2012-2390 huge pages: memory leak on mmap failure (rhbz 824352 824345) + +* Fri May 25 2012 Mauro Carvalho Chehab +- Don't manually customise tuners/frontends (rhbz 825203) + +* Thu May 24 2012 Josh Boyer +- CVE-2012-2372 mm: 32bit PAE pmd walk vs populate SMP race (rhbz 822821 822825) + +* Mon May 21 2012 Justin M. Forbes 3.3.7-1 +- Linux 3.3.7 + +* Fri May 18 2012 Josh Boyer +- Additional fixes for CVE-2011-4131 (rhbz 822874 822869) + +* Thu May 17 2012 Josh Boyer +- Fix rtlwifi async firmware load race condition (rhbz 822120) + +* Wed May 16 2012 Justin M. Forbes 3.3.6-3 +- fix rtl8187: ->brightness_set can not sleep (rhbz 795176) + +* Tue May 15 2012 Josh Boyer +- Fixup atl1c register programming (rhbz 749276) + +* Mon May 14 2012 Justin M. Forbes 3.3.6-1 +- Linux 3.3.6 + +* Mon May 07 2012 Mauro Carvalho Chehab 3.3.5-2 +- Add patch to fix DVB-S zigzag (rhbz 814404) + +* Mon May 07 2012 Josh Boyer 3.3.5-1 +- Linux 3.3.5 +- Add patch to rate limit NFSv4 message (rhbz 732748) + +* Fri May 04 2012 Josh Boyer +- unfiltered netdev rio_ioctl access by users (rhbz 818820) + +* Thu May 03 2012 Justin M. Forbes 3.3.4-3 +- Reenable slip for F16 (rhbz 818308) + +* Thu May 03 2012 Justin M. Forbes 3.3.4-3 +- Many patches from 3.3.5 stable queue +- NFS Bugfixes from upstream + +* Mon Apr 30 2012 Josh Boyer +- Backport ipw2x00 nl80211 cipher suite reporting (rhbz 817298) + +* Mon Apr 30 2012 Dave Jones +- Disable CONFIG_RCU_FAST_NO_HZ for now. (rhbz 806548) + +* Fri Apr 27 2012 Justin M. Forbes 3.3.4-1 +- Linux 3.3.4 + +* Tue Apr 24 2012 Josh Boyer +- Add patch to fix perf build due to incorrect cherry-pick in 3.3.3 +- Add patch to fix ipw2200 (rhbz 783708) + +* Mon Apr 23 2012 Peter Hutterer +- Fix regression on clickpads + +* Mon Apr 23 2012 Josh Boyer +- Linux 3.3.3 + +* Sat Apr 21 2012 Josh Boyer - 3.3.2-6 +- Fix error check in memblock that prevented boot on various Dells (rhbz 811225) + +* Fri Apr 20 2012 Josh Boyer +- CVE-2012-2123 fcaps: clear the same personality flags as suid when fcaps + are used (rhbz 814523 806722) + +* Thu Apr 19 2012 Justin M. Forbes - 3.3.2-4 +- CVE-2012-2119 macvtap: zerocopy: vector length is not validated before + pinning user pages (rhbz 814278 814289) + +* Thu Apr 19 2012 Justin M. Forbes +- Fix KVM device assignment page leak (rhbz 814149 814155) + +* Wed Apr 18 2012 Josh Boyer +- Change patch to resolve libata hotplug (rhbz 807632) +- Disable CONFIG_HID_BATTERY_STRENGTH (rhbz 806295) + +* Tue Apr 17 2012 Mauro Carvalho Chehab +- Fix DVB-S2->DVB-S switch regression (rhbz 812895) + +* Tue Apr 17 2012 Josh Boyer +- Fix oops in nfs_have_delegation (rhbz 811138) +- Fix oops on invalid AMD microcode load (rhbz 797559) + +* Sat Apr 14 2012 Josh Boyer +- Add ALSA quirk for MacPro 5,1 machines (rhbz 808559) + +* Fri Apr 13 2012 Josh Boyer - 3.3.2-1 +- Linux 3.3.2 + +* Tue Apr 10 2012 Josh Boyer +- Apply upstream patch to add USB device 13d3:3375 (rhbz 811087) + +* Tue Apr 10 2012 Mauro Carvalho Chehab +- Backport dvb-core and a few driver fixes from media tree (rhbz808871) + +* Tue Apr 10 2012 Josh Boyer +- Backport fixes for correct register constraints in cmpxchg.h (rhbz 809014) + +* Tue Apr 10 2012 Mauro Carvalho Chehab +- Update media tree to what's there at Kernel 3.4-rc2 + fixes for -rc3 + +* Thu Apr 05 2012 Dave Jones +- Better watermark the number of pages used by hibernation I/O (Bojan Smojver) (rhbz 785384) + +* Wed Apr 04 2012 Josh Boyer - 3.3.1-3 +- Disable runtime PM for hotpluggable ATA ports (rhbz 806676 807632) +- Disable MID_PTI driver (rhbz 783561) +- Fix NULL pointer dereference in i2400m (rhbz 808603) + +* Tue Apr 03 2012 Josh Boyer +- Fix crash in uvc_video_clock_update from Laurent Pinchart (rhbz 806433) + +* Mon Apr 02 2012 Dave Jones 3.3.1-2 +- Disable CONFIG_DEBUG_PAGEALLOC in -debug builds again. + +* Mon Apr 02 2012 Dave Jones +- Add patch to display more debug info for bug 808990. + +* Mon Apr 02 2012 Dave Jones 3.3.1-1 +- Linux 3.3.1 + +* Fri Mar 30 2012 Dave Jones +- Silence the timekeeping "Adjusting tsc more then 11%" spew. (rhbz 798600) + +* Fri Mar 30 2012 Josh Boyer +- Fix i915 fbdev cursor blink around suspend/hibernate from Dave Airlied +- CVE-2012-1601: kvm: NULL dereference from irqchip_in_kernel and + vcpu->arch.apic inconsistency (rhbz 808207) +- Add patch to fix incorrect buffer length in __nfs4_get_acl_uncached + +* Thu Mar 29 2012 Josh Boyer - 3.3.0-8 +- Drop __cpuinitdata on disable_nx for x86_32 (rhbz 808075) +- iwl{wifi,legacy}: Fix warnings on remove interface from Stanislaw Gruszka + (rhbz 770467) + +* Wed Mar 28 2012 Josh Boyer +- Fix disabled ASPM regression + +* Wed Mar 28 2012 Dave Jones +- Don't bind the IPS driver if no irq is assigned (typically BIOS bug). (rhbz 804353) + +* Tue Mar 27 2012 Josh Boyer +- Implement xen apic_ops to fix early crash in Xen Dom0 (rhbz 804347) +- Apply patch to fix MCE rcu splat (rhbz 789644) + +* Fri Mar 23 2012 Dave Jones +- Apply patches that should solve the bluetooth use-after-free oopses. (rhbz 806033) + +* Wed Mar 21 2012 Josh Boyer +- Ship hmac file for vmlinuz for FIPS-140 (rhbz 805538) + +* Tue Mar 20 2012 Josh Boyer +- CVE-2012-1568: execshield: predictable ascii armour base address (rhbz 804957) +- mac80211: fix possible tid_rx->reorder_timer use after free + from Stanislaw Gruska (rhbz 804007) + +* Mon Mar 19 2012 Adam Jackson - 3.3.0-2 +- drm-i915-dp-stfu.patch: Muzzle a bunch of DP WARN()s. They're not wrong, + but they're not helpful at this point. + +* Mon Mar 19 2012 Josh Boyer - 3.3.0-1 +- Linux 3.3 +- Drop compat-wireless infrastructure in preparation for 3.3 rebase + +* Fri Mar 16 2012 Justin M. Forbes +- re-enable threading on hibernate compression/decompression + +* Fri Mar 16 2012 Josh Boyer +- Fix irqpoll patch to really only apply for ASM108x machines (rhbz 800520) + +* Thu Mar 15 2012 Justin M. Forbes - 3.2.10-3 +- CVE-2012-1179 fix pmd_bad() triggering in code paths holding mmap_sem read mode (rhbz 803809) + +* Wed Mar 14 2012 Josh Boyer +- Fixup irqpoll patch to only activate on machines with ASM108x PCI bridge + +* Wed Mar 14 2012 Steve Dickson +- Reduce the foot print of the NFSv4 idmapping coda (bz 593035) + +* Mon Mar 12 2012 Josh Boyer - 3.2.10-1 +- Linux 3.2.10 + +* Mon Mar 12 2012 Josh Boyer - 3.2.9-4 +- Add patch to ignore bogus io-apic entries (rhbz 801501) + +* Wed Mar 07 2012 Dave Jones +- Add debug patch for bugs 787171/766277 + +* Wed Mar 07 2012 Josh Boyer +- CVE-2012-1146: memcg: unregister events attached to the same eventfd can + oops (rhbz 800817) + +* Mon Mar 05 2012 Josh Boyer +- CVE-2012-1097 regset: Prevent null pointer reference on readonly regsets +- Add patch to fix BUG_ON mm->nr_ptes (rhbz 786632) + +* Fri Mar 02 2012 Dave Jones +- Enable VM debugging in non-debug kernels too. + +* Fri Mar 02 2012 Justin M. Forbes +- Disable threading in hibernate compression/decompression + +* Fri Mar 02 2012 Adam Jackson +- drm-intel-crtc-dpms-fix.patch: Fix system hang on gen2 kit on DPMS (#730853) + +* Thu Mar 01 2012 Dave Jones +- Temporarily enable CONFIG_DEBUG_PAGEALLOC in -debug builds to help track + down some long-standing bugs. + Note: This will make -debug builds even slower than normal. + +* Thu Mar 01 2012 Dave Jones +- temporarily switch to low-performance polling IRQ mode when + unexpected IRQs occur. + +* Wed Feb 29 2012 Josh Boyer 3.2.9-1 +- Linux 3.2.9 + +* Tue Feb 28 2012 Josh Boyer 3.2.8-3 +- Add patch to enable keyboard backlight on Sony laptops (rhbz 728478) + +* Tue Feb 28 2012 Justin M. Forbes 3.2.8-2 +- CVE-2012-1090 CIFS: fix dentry refcount leak when opening a FIFO on lookup (rhbz 798296) + +* Mon Feb 27 2012 Josh Boyer 3.2.8-1 +- Linux 3.2.8 + +* Mon Feb 27 2012 Josh Boyer +- Add patch to fix regression in FADT revision checks (rhbz 730007 727865) + +* Fri Feb 24 2012 John W. Linville +- mac80211: call rate control only after init +- mac80211: do not call rate control .tx_status before .rate_init +- mwifiex: clear previous security setting during association +- ath9k: stop on rates with idx -1 in ath9k rate control's .tx_status +- ath9k_hw: prevent writes to const data on AR9160 +- rt2x00: fix a possible NULL pointer dereference +- iwlwifi: fix key removal +- mac80211: zero initialize count field in ieee80211_tx_rate +- mac80211: Fix a warning on changing to monitor mode from STA +- brcm80211: smac: fix endless retry of A-MPDU transmissions +- brcm80211: smac: only print block-ack timeout message at trace level + +* Mon Feb 20 2012 Dave Jones 3.2.7-1 +- Do not call drivers when invalidating partitions for -ENOMEDIUM + +* Mon Feb 20 2012 Dave Jones +- Linux 3.2.7 + +* Mon Feb 20 2012 Dave Jones +- NFSv4: Fix an Oops in the NFSv4 getacl code + +* Fri Feb 17 2012 Dave Jones +- improve handling of null rate in LIS3LV02Dx accelerometer driver. (rhbz 785814) + +* Fri Feb 17 2012 Dave Jones +- Reenable radio drivers. (rhbz 784824) + +* Thu Feb 16 2012 Dave Jones 3.2.6-4 +- Freeze all filesystems during system suspend/hibernate. + +* Wed Feb 15 2012 Josh Boyer +- Require newer linux-firmware for updated bnx2/bnx2x drivers + +* Tue Feb 14 2012 Josh Boyer +- Patch to enable CONFIG_KEYS_COMPAT on s390 from David Howells (rhbz 790367) + +* Mon Feb 13 2012 Dave Jones 3.2.6-3 +- Linux 3.2.6 + +* Mon Feb 13 2012 John W. Linville +- mwifiex: handle association failure case correctly +- ath9k: Fix kernel panic during driver initilization +- mwifiex: add NULL checks in driver unload path +- bcma: don't fail for bad SPROM CRC +- zd1211rw: firmware needs duration_id set to zero for non-pspoll frames +- mac80211: Fix a rwlock bad magic bug +- rtlwifi: Modify rtl_pci_init to return 0 on success + +* Fri Feb 10 2012 Josh Boyer +- Patch to prevent NULL pointer dereference in sd_revalidate_disk (rhbz 754518) + +* Thu Feb 09 2012 Dave Jones +- bsg: fix sysfs link remove warning (#787862) + +* Wed Feb 08 2012 Josh Boyer +- Fix e1000e Tx hang check (rhbz 785806) +- CVE-2011-4086 jbd2: unmapped buffer with _Unwritten or _Delay flags set can + lead to DoS (rhbz 788260) + +* Tue Feb 07 2012 Josh Boyer +- Make build/ point to /usr/src/kernels instead of being relative (rhbz 788125) + +* Mon Feb 06 2012 Josh Boyer +- Linux 3.2.5. Happy Birthday + +* Mon Feb 06 2012 John W. Linville +- ath9k: fix a WEP crypto related regression +- ath9k_hw: fix a RTS/CTS timeout regression + +* Sun Feb 05 2012 Dave Jones +- Remove unnecessary block-stray-block-put-after-teardown.patch +- readahead: fix pipeline break caused by block plug + +* Fri Feb 03 2012 Josh Boyer 3.2.3-2 +- Drop patch that was NAKed upstream (rhbz 783211) + +* Fri Feb 3 2012 John W. Linville +- bcma: Fix mem leak in bcma_bus_scan() +- rt2800lib: fix wrong -128dBm when signal is stronger than -12dBm +- iwlwifi: make "Tx aggregation enabled on ra =" be at DEBUG level +- ssb: fix cardbus slot in hostmode +- mac80211: timeout a single frame in the rx reorder buffer + +* Fri Feb 03 2012 Dave Jones 3.2.3-1 +- Linux 3.2.3 + +* Fri Feb 03 2012 Josh Boyer +- Patch from Jakub Kicinski to fix rt2x00 MCU requests (rhbz 772772) + +* Wed Feb 1 2012 John W. Linville +- Use "iwlwifi: don't mess up QoS counters with non-QoS frames" (rhbz 785239) +- Actually apply patch to make integrated compat-wireless avoid taint... + +* Tue Jan 31 2012 John W. Linville +- Apply iwlwifi patch for TID issue (rhbz 785239) + +* Mon Jan 30 2012 Dave Jones +- Enable kmemleak (off by default) in kernel-debug (rhbz 782419) + +* Mon Jan 30 2012 Dave Jones +- Restore the Savage DRM and several others that were accidentally + early-deprecated. + +* Mon Jan 30 2012 John W. Linville +- Use the eeprom_93cx6 driver from the compat-wireless package +- mac80211: fix debugfs key->station symlink +- brcmsmac: fix tx queue flush infinite loop +- mac80211: Use the right headroom size for mesh mgmt frames +- mac80211: fix work removal on deauth request +- b43: add option to avoid duplicating device support with brcmsmac +- mac80211: update oper_channel on ibss join +- mac80211: set bss_conf.idle when vif is connected +- iwlwifi: fix PCI-E transport "inta" race +- ath9k: use WARN_ON_ONCE in ath_rc_get_highest_rix + +* Fri Jan 27 2012 John W. Linville +- Include config.mk from compat-wireless build in files for installation + +* Wed Jan 25 2012 Josh Boyer - 3.2.2-1 +- Linux 3.2.2 +- Add patch to invalidate parent cache when fsync is called on a partition + (rhbz 783211) +- Test fix for realtek_async_autopm oops from Stanislaw Gruszka (rhbz 784345) + +* Wed Jan 25 2012 John W. Linville +- modpost: add option to allow external modules to avoid taint +- Make integrated compat-wireless take advantage of the above + +* Wed Jan 25 2012 Josh Boyer +- Backport patch to fix oops in rds (rhbz 718790) + +* Tue Jan 24 2012 John W. Linville +- Update compat-wireless snapshot to version 3.3-rc1-2 + +* Tue Jan 24 2012 Josh Boyer +- Re-enable the ARCMSR module (rhbz 784287) +- Add back a set of patches that were erroneously dropped during the rebase +- Re-enable the LIRC_STAGING drivers (rhbz 784398) + +* Mon Jan 23 2012 Josh Boyer 3.2.1-3 +- Fix oops in iwlwifi/iwlagn driver (rhbz 766071) +- Fix NULL pointer dereference in sym53c8xx module (rhbz 781625) + +* Fri Jan 20 2012 Dave Jones +- net: reintroduce missing rcu_assign_pointer() calls + +* Fri Jan 20 2012 Josh Boyer +- Add mac80211 deauth fix pointed out by Stanislaw Gruszka + +* Thu Jan 19 2012 Dave Jones 3.2.1-1 +- Rebase to Linux 3.2.1 + +* Thu Jan 19 2012 John W. Linville +- Pass the same make options to compat-wireless as to the base kernel + +* Wed Jan 18 2012 Josh Boyer 3.1.10-2 +- Fix broken procfs backport (rhbz 782961) + +* Wed Jan 18 2012 Josh Boyer 3.1.10-1 +- Linux 3.1.10 +- /proc/pid/* information leak (rhbz 782686) +- CVE-2012-0056 proc: clean up and fix /proc//mem (rhbz 782681) +- loop: prevent information leak after failed read (rhbz 782687) + +* Tue Jan 17 2012 Josh Boyer +- CVE-2011-4127 possible privilege escalation via SG_IO ioctl (rhbz 769911) + +* Mon Jan 16 2012 John W. Linville +- Re-apply patch to revert mac80211 scan optimizations (rhbz #731365, #773271) + +* Sun Jan 15 2012 Josh Boyer +- Avoid packaging symlinks for kernel-doc files (rhbz 767351) +- Apply mac80211 NULL ptr deref fix to compat-wireless too (rhbz 769766) + +* Fri Jan 13 2012 Josh Boyer +- Fix verbose logging messages in the rtl8192cu driver (rhbz 728740) + +* Fri Jan 13 2012 Josh Boyer 3.1.9-1 +- Linux 3.1.9 +- CVE-2012-0045 kvm: syscall instruction induced guest panic (rhbz 773392) + +* Wed Jan 11 2012 Josh Boyer +- Patch from Stanislaw Gruszka to fix NULL ptr deref in mac80211 (rhbz 769766) + +* Tue Jan 10 2012 John W. Linville +- Update compat-wireless snapshot to version 3.2-1 + +* Tue Jan 10 2012 Josh Boyer +- Add patch to fix ext4 compatibility with ext2 mount option (rhbz 770172) +- Fix ext4 corrupted bitmap error path (pointed out by Eric Sandeen) + +* Sat Jan 07 2012 Josh Boyer 3.1.8-2 +- Add iwlwifi-allow-to-switch-to-HT40-if-not-associated.patch back to + compat-wireless + +* Fri Jan 06 2012 Josh Boyer 3.1.8-1 +- Disable backports on arches where we don't actually build a kernel (or config) +- Linux 3.1.8 + +* Thu Jan 05 2012 John W. Linville +- Patch compat-wireless build to avoid "pr_fmt redefined" warnings +- Include compat-wireless in removal of files resulting from patch fuzz + +* Thu Jan 05 2012 Josh Boyer +- Move the depmod file removal below the compat-wireless build to make sure we + clean them all out + +* Wed Jan 04 2012 Neil Horman +- Fix warning about msi sysfs refcount (bz 771058) + +* Wed Jan 04 2012 Dave Jones +- Disable PCI CRS blacklist patch +- Try alternative approach from Bjorn Helgaas to work around + MCFG quirks on some laptops. + +* Wed Jan 04 2012 Dave Jones +- Add Dell Studio 1557 to pci=nocrs blacklist. (rhbz 769657) + +* Wed Jan 04 2012 Josh Boyer +- CVE-2011-4347 kvm: device assignment DoS (rhbz 771678) + +* Tue Jan 03 2012 Josh Boyer 3.1.7-1 +- Linux 3.1.7 + +* Tue Jan 03 2012 John W. Linville +- Avoid unnecessary modprobe invocations during compat-wireless build + +* Tue Jan 03 2012 Dave Jones +- Add Thinkpad SL510 to the pci=nocrs blacklist. + +* Tue Jan 03 2012 Josh Boyer +- CVE-2011-4622 kvm: pit timer with no irqchip crashes the system (rhbz 771387) +- Add bluetooth support for BCM20102A0 (rhbz 770233) + +* Tue Jan 03 2012 Dave Jones +- thp: reduce khugepaged freezing latency (rhbz 771006) + +* Tue Jan 3 2012 John W. Linville +- Re-enable CONFIG_RT2800PCI_RT53XX in compat-wireless build (rhbz #720594) + +* Thu Dec 29 2011 Dave Jones 3.1.6-2 +- Create a blacklist for pci=nocrs + Add Dell Studio 1536 to it. + +* Fri Dec 23 2011 Dennis Gilmore +- build imx highbank and kirkwood kernels for arm + +* Thu Dec 22 2011 John W. Linville +- iwlwifi: do not set the sequence control bit is not needed +- ath9k: fix max phy rate at rate control init +- mwifiex: avoid double list_del in command cancel path +- iwlwifi: update SCD BC table for all SCD queues + +* Wed Dec 21 2011 Dave Jones 3.1.6-1 +- Linux 3.1.6 + +* Wed Dec 21 2011 John W. Linville +- Apply some iwlwifi regression fixes not in the 3.2-rc6 wireless snapshot +- Turn-off with_backports for s390x + +* Wed Dec 21 2011 Dave Jones 3.1.5-11 +- Reinstate the route cache garbage collector. + +* Wed Dec 21 2011 John W. Linville +- Revise compat-wireless configuration +- Enable with-backports by default +- Update compat-wireless snaptshot from verstion 3.2-rc6-3 + +* Tue Dec 20 2011 Dave Jones 3.1.5-10 +- Delay after aborting command in tpm_tis (rhbz #746097) + +* Tue Dec 20 2011 Josh Boyer +- Backport upstream fix for b44_poll oops (rhbz #741117) +- Include crtsaves.o for ppc64 as well (rhbz #769415) +- Drop EDID headers patch from 751589 for now (rhbz #769103) + +* Mon Dec 19 2011 Kyle McMartin - 3.1.5-8 +- Add versioned Obsoletes and Provides for kernel-tools -> perf, hopefully + this should allow upgrades from kernel-tools to perf+kernel-tools in rawhide + from F-16. + +* Mon Dec 19 2011 Dave Jones +- x86, dumpstack: Fix code bytes breakage due to missing KERN_CONT + +* Fri Dec 16 2011 Ben Skeggs - 3.1.5-7 +- Add patch to do a better job of dealing with busted EDID headers (rhbz#751589) + +* Thu Dec 15 2011 Josh Boyer - 3.1.5-6 +- Add patch to fix Intel wifi regression in 3.1.5 (rhbz 767173) + +* Thu Dec 15 2011 Dave Jones - 3.1.5-5 +- Change configfs to be built-in. (rhbz 767857) + +* Thu Dec 15 2011 Dave Jones - 3.1.5-4 +- Disable Intel IOMMU by default. + +* Tue Dec 13 2011 Josh Boyer +- Remove extraneous settings and enable Radeon KMS for powerpc (via Will Woods) + +* Mon Dec 12 2011 Josh Boyer +- Add patch from Jeff Layton to fix suspend with NFS (rhbz #717735) +- Backport ALPS touchpad patches from input/next branch (rhbz #590880) + +* Fri Dec 09 2011 Josh Boyer 3.1.5-1 +- Linux 3.1.5 + +* Thu Dec 08 2011 Chuck Ebbert 3.1.5-0.rc2.1 +- Linux 3.1.5-rc2 +- Drop obsolete changelog, set rcrev and gitrev to 0 so they're + less distracting. +- Fix wrong link speed on some sky2 network adapters (rhbz #757839) + +* Thu Dec 08 2011 Ben Skeggs 3.1.5-0.rc1.2 +- nouveau: fix accel on GF108 and enable on GF108/GF110 + +* Wed Dec 07 2011 Chuck Ebbert +- Linux 3.1.5-rc1 +- Comment out merged patches: + xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch + rtlwifi-fix-lps_lock-deadlock.patch + +* Tue Dec 06 2011 Chuck Ebbert +- Disable uas until someone can fix it (rhbz #717633) + +* Tue Dec 06 2011 Josh Boyer +- Add reworked pci ASPM patch from Matthew Garrett + +* Mon Dec 05 2011 Josh Boyer +- Only print the apm_cpu_idle message once (rhbz #760341) + +* Mon Dec 05 2011 Dave Jones +- Switch from -Os to -O2 + +* Thu Dec 01 2011 Josh Boyer +- Apply patch to revert mac80211 scan optimizations (rhbz #731365) +- Disable the existing brcm80211 staging drivers (rhbz #759109) + +* Wed Nov 30 2011 Josh Boyer +- Include commit 3940d6185 from JJ Ding in elantech.patch + +* Tue Nov 29 2011 Josh Boyer +- Add patch to fix deadlock in rtlwifi (rhbz #755154) +- Drop drm-intel-make-lvds-work.patch (rhbz #731296) + +* Mon Nov 28 2011 Chuck Ebbert 3.1.4-1 +- Linux 3.1.4 + +* Mon Nov 28 2011 Chuck Ebbert +- Fix IRQ error preventing load of cciss module (rhbz#754907) + +* Mon Nov 28 2011 Ben Skeggs 3.1.3-2 +- nouveau: fix two instances of an oops in ttm clear() (rhbz#751753) + +* Sun Nov 27 2011 Chuck Ebbert 3.1.3-1 +- Linux 3.1.3 + +* Wed Nov 23 2011 Chuck Ebbert 3.1.3-0.rc1.1 +- Linux 3.1.3-rc1 +- Comment out merged patches: + usb-add-quirk-for-logitech-webcams.patch + ip6_tunnel-copy-parms.name-after-register_netdevice.patch + +* Tue Nov 22 2011 Chuck Ebbert 3.1.2-1 +- Linux 3.1.2 + +* Sat Nov 19 2011 Chuck Ebbert 3.1.2-0.rc1.1 +- Linux 3.1.2-rc1 + +* Wed Nov 16 2011 John W. Linville +- Add compat-wireless as an option for kernel build + +* Tue Nov 15 2011 Dave Jones +- mm: Do not stall in synchronous compaction for THP allocations + +* Tue Nov 15 2011 Dave Jones +- Backport asus-laptop changes from 3.2 (rhbz 754214) + +* Mon Nov 14 2011 Josh Boyer +- Patch from Joshua Roys to add rtl8192* to modules.networking (rhbz 753645) +- Add patch for wacom tablets for Bastien Nocera (upstream 3797ef6b6) +- Add patch to fix ip6_tunnel naming (rhbz 751165) +- Quite warning in apm_cpu_idle (rhbz 753776) + +* Mon Nov 14 2011 Josh Boyer 3.1.1-2 +- CVE-2011-4131: nfs4_getfacl decoding kernel oops (rhbz 753236) +- CVE-2011-4132: jbd/jbd2: invalid value of first log block leads to oops (rhbz 753346) + +* Fri Nov 11 2011 Chuck Ebbert +- Use the same naming scheme as rawhide for -stable RC kernels + (e.g. 3.1.1-0.rc1.1 instead of 3.1.1-1.rc1) + +* Fri Nov 11 2011 Josh Boyer 3.1.1-1 +- Linux 3.1.1 + +* Fri Nov 11 2011 John W. Linville +- Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 + +* Thu Nov 10 2011 Chuck Ebbert +- Sync samsung-laptop driver with what's in 3.2 (rhbz 747560) + +* Wed Nov 09 2011 Chuck Ebbert 3.1.1-1.rc1 +- Linux 3.1.1-rc1 +- Comment out merged patches, will drop when release is final: + ums-realtek-driver-uses-stack-memory-for-DMA.patch + epoll-fix-spurious-lockdep-warnings.patch + crypto-register-cryptd-first.patch + add-macbookair41-keyboard.patch + powerpc-Fix-deadlock-in-icswx-code.patch + iwlagn-fix-ht_params-NULL-pointer-dereference.patch + mmc-Always-check-for-lower-base-frequency-quirk-for-.patch + media-DiBcom-protect-the-I2C-bufer-access.patch + media-dib0700-protect-the-dib0700-buffer-access.patch + WMI-properly-cleanup-devices-to-avoid-crashes.patch + mac80211-fix-remain_off_channel-regression.patch + mac80211-config-hw-when-going-back-on-channel.patch + +* Wed Nov 09 2011 John W. Linville +- Backport brcm80211 from 3.2-rc1 + +* Tue Nov 08 2011 Neil Horman +- Add msi irq ennumeration per device in sysfs (rhbz 752176) + +* Mon Nov 07 2011 Josh Boyer +- Add two patches to fix mac80211 issues (rhbz 731365) + +* Thu Nov 03 2011 Josh Boyer +- Add commits queued for 3.2 for elantech driver (rhbz 728607) +- Fix crash when setting brightness via Fn keys on ideapads (rhbz 748210) + +* Wed Nov 02 2011 Josh Boyer +- Add patch to fix oops when removing wmi module (rhbz 706574) + +* Tue Nov 01 2011 Dave Jones 3.1.0-8 +- allow building the perf rpm for ARM (rhbz 741325) + +* Tue Nov 01 2011 Dave Jones 3.1.0-8 +- Add another Sony laptop to the nonvs blacklist. (rhbz 641789) + +* Tue Nov 1 2011 Josh Boyer 3.1.0-7 +- Drop x86-efi-Calling-__pa-with-an-ioremap-address-is-invalid (rhbz 748516) + +* Mon Oct 31 2011 Josh Boyer +- CVE-2011-4097: oom_badness() integer overflow (rhbz 750402) + +* Fri Oct 28 2011 Josh Boyer +- Add patch to prevent tracebacks on a warning in floppy.c (rhbz 749887) + +* Wed Oct 26 2011 Fedora Release Engineering - 3.1.0-5 +- Rebuilt for glibc bug#747377 + +* Wed Oct 26 2011 Josh Boyer +- CVE-2011-4077: xfs: potential buffer overflow in xfs_readlink() (rhbz 749166) + +* Tue Oct 25 2011 Josh Boyer +- CVE-2011-3347: be2net: promiscuous mode and non-member VLAN packets DoS (rhbz 748691) +- CVE-2011-1083: excessive in kernel CPU consumption when creating large nested epoll structures (rhbz 748668) + +* Mon Oct 24 2011 Josh Boyer +- Backport 3 fixed from linux-next to fix dib0700 playback (rhbz 733827) + +* Mon Oct 24 2011 Chuck Ebbert 3.1.0-1 +- Linux 3.1 + +* Fri Oct 21 2011 Chuck Ebbert 3.1.0-0.rc10.git1.1 +- Update to upstream HEAD (v3.1-rc10-42-g2efd7c0) + +* Fri Oct 21 2011 Dave Jones +- Lower severity of Radeon lockup messages. + +* Wed Oct 19 2011 Dave Jones +- Add Sony VGN-FW21E to nonvs blacklist. (rhbz 641789) + +* Wed Oct 19 2011 Chuck Ebbert 3.1.0-0.rc10.git0.1 +- Fix divide-by-zero in nouveau driver (rhbz #747129) + +* Tue Oct 18 2011 Chuck Ebbert +- Fix lock inversion causing hangs in 3.1-rc9 (rhbz #746485) +- Linux 3.1-rc10 + +* Tue Oct 18 2011 Josh Boyer +- Add patch to fix invalid EFI remap calls from Matt Fleming + +* Mon Oct 17 2011 Josh Boyer +- Add two patches to fix stalls in khugepaged (rhbz 735946) + +* Thu Oct 13 2011 Josh Boyer +- Update usb-add-quirk-for-logitech-webcams.patch with C600 ID (rhbz 742010) + +* Thu Oct 13 2011 Adam Jackson +- drm/i915: Treat SDVO LVDS as digital when parsing EDID (#729882) + +* Thu Oct 13 2011 Josh Boyer +- Add patch from Stanislaw Gruszka to fix iwlagn NULL dereference (rhbz 744155) + +* Tue Oct 11 2011 Josh Boyer +- Disable CONFIG_XEN_BALLOON_MEMORY_HOTPLUG (rhbz 744408) + +* Thu Oct 06 2011 Josh Boyer +- Add patch to fix base frequency check for Ricoh e823 devices (rhbz 722509) + +* Thu Oct 06 2011 Dave Jones +- Taint if virtualbox modules have been loaded. + +* Wed Oct 05 2011 Chuck Ebbert 3.1.0-0.rc9.git0.0 +- Linux 3.1-rc9 + +* Mon Oct 03 2011 Chuck Ebbert 3.1.0-0.rc8.git0.1 +- block: Free queue resources at blk_release_queue() + +* Thu Sep 29 2011 Chuck Ebbert +- Require grubby >= 8.3-1 so initrd line gets added (rhbz #725185) + +* Thu Sep 29 2011 Josh Boyer +- Update logitech USB quirk patch + +* Tue Sep 27 2011 Chuck Ebbert 3.1.0-0.rc8.git0.0 +- Linux 3.1-rc8 +- New option: CONFIG_ARM_ERRATA_764369 is not set +- Fix up utrace.patch to apply after commit f9d81f61c + +* Thu Sep 22 2011 Dave Jones +- Make CONFIG_XEN_PLATFORM_PCI=y (rhbz 740664) + +* Thu Sep 22 2011 Dennis Gilmore +- build vmlinux image for sparc64 + +* Wed Sep 21 2011 Josh Boyer +- Linux 3.1-rc7 + +* Tue Sep 20 2011 Dave Jones +- Limit 32-bit x86 kernels to 32 processors. + +* Tue Sep 20 2011 Ben Skeggs 3.1.0-0.rc6.git0.4.fc16 +- nouveau: patch in updates queued for 3.2, mostly new hw support (GF116/GF119) + +* Fri Sep 16 2011 Josh Boyer 3.1.0-0.rc6.git0.3.fc16 +- Add patch to fix deadlock in ipw2x00 (rhbz 738387) +- Fixup kernel-tools file section for ppc/ppc64 + +* Thu Sep 15 2011 Josh Boyer +- CVE-2011-3191: cifs: fix possible memory corruption in CIFSFindNext + +* Wed Sep 14 2011 Josh Boyer +- Add patch to fix deadlock in ppc64 icswx (rhbz 737984) + +* Wed Sep 14 2011 Neil Horman +- Enable CONFIG_IP_VS_IPV6 (bz 738194) + +* Wed Sep 14 2011 Josh Boyer +- Add support for Macbook Air 4,1 keyboard, trackpad, and bluetooth +- Add patch to fix HVCS on ppc64 (rhbz 738096) +- Add various ibmveth driver fixes (rhbz 733766) + +* Tue Sep 13 2011 Adam Jackson +- drm/i915: Shut the fbc messages up when drm.debug & 4 + +* Mon Sep 12 2011 Josh Boyer 3.1.0-0.rc6.git0.0 +- Linux 3.1-rc6 (contains the fix for 737076) +- Disable debug builds + +* Fri Sep 09 2011 Josh Boyer +- Change to 64K page size for ppc64 kernels (rhbz 736751) + +* Fri Sep 09 2011 Josh Boyer 3.1.0-0.rc5.git0.0 +- Linux 3.1-rc5 + +* Wed Sep 07 2011 Josh Boyer +- Add patch to fix oops when linking entities in ucvideo (rhbz 735437) + +* Fri Sep 02 2011 Dave Jones +- Apply patch to fix lockdep reports from ext4 (rhbz 732572) + +* Thu Sep 01 2011 Dave Jones +- utrace: s390: fix the compile problem with traps.c (rhbz 735118) + +* Tue Aug 30 2011 Dave Jones +- Revert "x86: Serialize EFI time accesses on rtc_lock" (rhbz 732755) + +* Tue Aug 30 2011 Josh Boyer +- Add patch to fix rhbz 606017 + +* Mon Aug 29 2011 Josh Boyer +- Linux 3.1-rc4 + +* Sat Aug 27 2011 Dave Jones +- Fix get_gate_vma usage in i386 NX emulation +- Bring back the 32bit mmap randomization patch for now. + NX emulation is still too dependant upon it. + +* Fri Aug 26 2011 Dave Jones +- Enable CONFIG_DETECT_HUNG_TASK for debug builds & rawhide. + +* Fri Aug 26 2011 Dave Jones +- Drop linux-2.6-debug-vm-would-have-oomkilled.patch + The oom-killer heuristics have improved enough that this should + never be necessary (and it probably doesn't dtrt any more) + +* Fri Aug 26 2011 Dave Jones +- Drop linux-2.6-32bit-mmap-exec-randomization.patch + Outlived it's usefulness (and made of ugly) + +* Fri Aug 26 2011 Dave Jones +- Drop acpi-ec-add-delay-before-write.patch (rhbz 733690) + +* Fri Aug 26 2011 Josh Boyer +- Linux 3.1-rc3-git5 + +* Wed Aug 24 2011 Josh Boyer +- Revert 'iwlwifi: advertise max aggregate size'. (rhbz 708747) + +* Mon Aug 22 2011 Josh Boyer +- Linux 3.1-rc3 +- Add patch to fix duplicate backlight registration (rhbz 732202) + +* Mon Aug 22 2011 Dave Jones +- Avoid false quiescent states in rcutree with CONFIG_RCU_FAST_NO_HZ. (rhbz 577968) + +* Sat Aug 20 2011 Josh Boyer +- Linux 3.1-rc2-git7 +- Add a provides/obsoletes for cpupowerutils-devel + +* Fri Aug 19 2011 Josh Boyer +- Add patch from upstream to fix 64-bit divide error in btrfs +- Add BuildRequires on gettext for cpupowerutils translations + +* Fri Aug 19 2011 Josh Boyer +- Linux 3.1-rc2-git5 +- Change XHCI to builtin (rhbz 731706) +- Add patch to fix race between cryptd and aesni (rhbz 721002) + +* Thu Aug 18 2011 Josh Boyer +- Adjust provides/obsoletes to replace the cpupowerutils package + +* Wed Aug 17 2011 Josh Boyer +- Create the kernel-tools subpackages based on a start by davej + +* Tue Aug 16 2011 Dave Jones +- Prepare for packaging more of tools/ by renaming 'perf' subpackage + to kernel-tools + +* Tue Aug 16 2011 Dennis Gilmore +- add config for arm tegra devices +- setup kernel to build omap image (patch from David Marlin) +- setup kernel to build tegra image based on omap work +- add arm device tree patches + +* Sat Aug 13 2011 Dave Jones +- CPU_FREQ drivers should now be built-in on x86-64. + +* Thu Aug 11 2011 Josh Boyer +- Add patch davej applied to f15 for rhbz 729340 +- Add munged together patch for rhbz 729269 +- Build ide_pmac as a module (rhbz 730039) + +* Tue Aug 09 2011 Josh Boyer +- Add Makefile.config and ARM config changes from David Marlin + +* Tue Aug 09 2011 Josh Boyer +- Add patch davej applied to f15 for rhbz 728872 + +* Tue Aug 09 2011 Dave Jones +- ptrace_report_syscall: check if TIF_SYSCALL_EMU is defined + +* Tue Aug 09 2011 Dave Jones +- Enable CONFIG_SAMSUNG_LAPTOP (rhbz 729363) + +* Mon Aug 08 2011 Josh Boyer +- Bring in utrace fixes davej applied to f15. (rhbz 728379) + +* Fri Aug 05 2011 Josh Boyer +- Adjust Makefile munging for new 3.x numbering scheme + +* Fri Aug 05 2011 Dave Jones +- Deselect CONFIG_DECNET. Unmaintained, and rubbish. + +* Fri Aug 05 2011 Josh Boyer +- 3.0.1 + +* Fri Aug 05 2011 Josh Boyer +- Add patch for rhbz 726701 from Matthew Garrett + +* Thu Aug 04 2011 Dave Jones +- Drop neuter_intel_microcode_load.patch (rhbz 690930) + +* Wed Aug 03 2011 John W. Linville +- Disable CONFIG_BCMA since no driver currently uses it (rhbz 727796) + +* Wed Aug 03 2011 Josh Boyer +- Add patch to fix backtrace in cdc_ncm driver (rhbz 720128) +- Add patch to fix backtrace in usm-realtek driver (rhbz 720054) + +* Tue Aug 02 2011 Josh Boyer +- Add patch to fix HFSPlus filesystem mounting (rhbz 720771) + +* Tue Aug 02 2011 Dave Jones +- Change USB_SERIAL_OPTION back to modular. (rhbz 727680) + +* Tue Aug 02 2011 Josh Boyer +- Fix epoll recursive lockdep warnings (rhbz 722472) +- Turn debug builds back on + +* Tue Aug 02 2011 Josh Boyer +- Add change from Yanko Kaneti to get the rt2x00 drivers in modules.networking + (rhbz 708314) + +* Fri Jul 29 2011 Dave Jones +- Fix scsi_dispatch_cmd oops (USB eject problems, etc). + +* Thu Jul 28 2011 Dave Jones +- module-init-tools needs to be a prereq, not a conflict. + +* Thu Jul 28 2011 Josh Boyer +- Backport patch to correct udlfb removal events (rhbz 726163) + +* Wed Jul 27 2011 Dave Jones +- Turn off debug builds. * Fri Jul 22 2011 Dave Jones - bootwrapper needs objcopy. Add it to requires: (wwoods) diff --git a/linux-2.6-32bit-mmap-exec-randomization.patch b/linux-2.6-32bit-mmap-exec-randomization.patch index 6008173b0..c25323323 100644 --- a/linux-2.6-32bit-mmap-exec-randomization.patch +++ b/linux-2.6-32bit-mmap-exec-randomization.patch @@ -152,7 +152,7 @@ Main executable randomisation (PIE) : 12 bits (guessed) struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c -@@ -124,13 +124,16 @@ static unsigned long mmap_legacy_base(void) +@@ -124,13 +124,19 @@ static unsigned long mmap_legacy_base(void) */ void arch_pick_mmap_layout(struct mm_struct *mm) { @@ -163,9 +163,12 @@ Main executable randomisation (PIE) : 12 bits (guessed) } else { mm->mmap_base = mmap_base(); mm->get_unmapped_area = arch_get_unmapped_area_topdown; ++#ifdef CONFIG_X86_32 + if (!(current->personality & READ_IMPLIES_EXEC) ++ && !(__supported_pte_mask & _PAGE_NX) + && mmap_is_ia32()) + mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; ++#endif mm->unmap_area = arch_unmap_area_topdown; } } @@ -224,3 +227,25 @@ Main executable randomisation (PIE) : 12 bits (guessed) if (new_addr & ~PAGE_MASK) { ret = new_addr; goto out; +diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c +index 57d1868..29c0c35 100644 +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -669,6 +669,16 @@ unsigned long arch_align_stack(unsigned long sp) + unsigned long arch_randomize_brk(struct mm_struct *mm) + { + unsigned long range_end = mm->brk + 0x02000000; +- return randomize_range(mm->brk, range_end, 0) ? : mm->brk; ++ unsigned long bump = 0; ++#ifdef CONFIG_X86_32 ++ /* in the case of NX emulation, shove the brk segment way out of the ++ way of the exec randomization area, since it can collide with ++ future allocations if not. */ ++ if ( (mm->get_unmapped_exec_area == arch_get_unmapped_exec_area) && ++ (mm->brk < 0x08000000) ) { ++ bump = (TASK_SIZE/6); ++ } ++#endif ++ return bump + (randomize_range(mm->brk, range_end, 0) ? : mm->brk); + } + diff --git a/linux-2.6-acpi-debug-infinite-loop.patch b/linux-2.6-acpi-debug-infinite-loop.patch index d20025224..f2cc1a55e 100644 --- a/linux-2.6-acpi-debug-infinite-loop.patch +++ b/linux-2.6-acpi-debug-infinite-loop.patch @@ -1,5 +1,5 @@ ---- linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h~ 2010-07-01 14:49:03.000000000 -0400 -+++ linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h 2010-07-01 14:49:17.000000000 -0400 +--- linux-2.6.34.noarch/include/acpi/acconfig.h~ 2010-07-01 14:49:03.000000000 -0400 ++++ linux-2.6.34.noarch/include/acpi/acconfig.h 2010-07-01 14:49:17.000000000 -0400 @@ -117,7 +117,7 @@ /* Maximum number of While() loop iterations before forced abort */ diff --git a/linux-2.6-crash-driver.patch b/linux-2.6-crash-driver.patch index b8377d321..239f0f6a0 100644 --- a/linux-2.6-crash-driver.patch +++ b/linux-2.6-crash-driver.patch @@ -1,17 +1,17 @@ -From df42d15cd28f468ecd4c30465b98a53cce90617c Mon Sep 17 00:00:00 2001 +From f72d640713d01b3b704c6e84ab49b62f19fc9c22 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 30 Mar 2010 00:16:25 -0400 -Subject: dev-crash-driver.patch +Subject: [PATCH] dev-crash-driver.patch --- arch/ia64/include/asm/crash.h | 90 +++++++++++++++++++++++++++++ arch/ia64/kernel/ia64_ksyms.c | 3 + arch/x86/include/asm/crash.h | 75 ++++++++++++++++++++++++ arch/x86/mm/ioremap.c | 2 + - drivers/char/Kconfig | 2 + + drivers/char/Kconfig | 3 + drivers/char/Makefile | 2 + drivers/char/crash.c | 128 +++++++++++++++++++++++++++++++++++++++++ - 7 files changed, 302 insertions(+), 0 deletions(-) + 7 files changed, 303 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/include/asm/crash.h create mode 100644 arch/x86/include/asm/crash.h create mode 100644 drivers/char/crash.c @@ -208,7 +208,7 @@ index 0000000..dfcc006 + +#endif /* _ASM_I386_CRASH_H */ diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c -index 5eb1ba7..3e525d2 100644 +index be1ef57..ac659f7 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -24,6 +24,8 @@ @@ -220,6 +220,30 @@ index 5eb1ba7..3e525d2 100644 /* * Fix up the linear direct mapping of the kernel to avoid cache attribute * conflicts. +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index 423fd56..e04a561 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -4,6 +4,9 @@ + + menu "Character devices" + ++config CRASH ++ tristate "Crash Utility memory driver" ++ + source "drivers/tty/Kconfig" + + config DEVKMEM +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 32762ba..3d5d525 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -65,3 +65,5 @@ obj-$(CONFIG_JS_RTC) += js-rtc.o + js-rtc-y = rtc.o + + obj-$(CONFIG_TILE_SROM) += tile-srom.o ++ ++obj-$(CONFIG_CRASH) += crash.o diff --git a/drivers/char/crash.c b/drivers/char/crash.c new file mode 100644 index 0000000..e5437de @@ -354,29 +378,6 @@ index 0000000..e5437de +module_exit(crash_cleanup_module); + +MODULE_LICENSE("GPL"); +-- +1.7.6 -diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index ba53ec9..6588b33 100644 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -98,3 +98,5 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o - - obj-$(CONFIG_JS_RTC) += js-rtc.o - js-rtc-y = rtc.o -+ -+obj-$(CONFIG_CRASH) += crash.o - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 04f8b2d..e8fb997 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -4,6 +4,9 @@ - - menu "Character devices" - -+config CRASH -+ tristate "Crash Utility memory driver" -+ - source "drivers/tty/Kconfig" - - config DEVKMEM diff --git a/linux-2.6-debug-taint-vm.patch b/linux-2.6-debug-taint-vm.patch deleted file mode 100644 index 672509db2..000000000 --- a/linux-2.6-debug-taint-vm.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 4e8985a..70d0853 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -318,6 +318,7 @@ static void bad_page(struct page *page) - current->comm, page_to_pfn(page)); - dump_page(page); - -+ print_modules(); - dump_stack(); - out: - /* Leave bad fields for debug, except PageBuddy could make trouble */ -diff --git a/mm/slab.c b/mm/slab.c -index d96e223..6f8905b 100644 ---- a/mm/slab.c -+++ b/mm/slab.c -@@ -1886,8 +1886,8 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp) - /* Print header */ - if (lines == 0) { - printk(KERN_ERR -- "Slab corruption: %s start=%p, len=%d\n", -- cachep->name, realobj, size); -+ "Slab corruption (%s): %s start=%p, len=%d\n", -+ print_tainted(), cachep->name, realobj, size); - print_objinfo(cachep, objp, 0); - } - /* Hexdump the affected line */ -@@ -2985,8 +2985,8 @@ static void check_slabp(struct kmem_cache *cachep, struct slab *slabp) - if (entries != cachep->num - slabp->inuse) { - bad: - printk(KERN_ERR "slab: Internal list corruption detected in " -- "cache '%s'(%d), slabp %p(%d). Hexdump:\n", -- cachep->name, cachep->num, slabp, slabp->inuse); -+ "cache '%s'(%d), slabp %p(%d). Tainted(%s). Hexdump:\n", -+ cachep->name, cachep->num, slabp, slabp->inuse, print_tainted()); - for (i = 0; - i < sizeof(*slabp) + cachep->num * sizeof(kmem_bufctl_t); - i++) { -diff --git a/mm/slub.c b/mm/slub.c -index 35f351f..e7ccb39 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -472,7 +472,7 @@ static void slab_bug(struct kmem_cache *s, char *fmt, ...) - va_end(args); - printk(KERN_ERR "========================================" - "=====================================\n"); -- printk(KERN_ERR "BUG %s: %s\n", s->name, buf); -+ printk(KERN_ERR "BUG %s (%s): %s\n", s->name, print_tainted(), buf); - printk(KERN_ERR "----------------------------------------" - "-------------------------------------\n\n"); - } diff --git a/linux-2.6-debug-vm-would-have-oomkilled.patch b/linux-2.6-debug-vm-would-have-oomkilled.patch deleted file mode 100644 index 8bd05ab06..000000000 --- a/linux-2.6-debug-vm-would-have-oomkilled.patch +++ /dev/null @@ -1,69 +0,0 @@ -From beb764ac03e52eba1a654afb4273fab1f9de3cff Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 29 Nov 2010 20:59:14 -0500 -Subject: [PATCH] linux-2.6-debug-vm-would_have_oomkilled - ---- - include/linux/oom.h | 1 + - kernel/sysctl.c | 7 +++++++ - mm/oom_kill.c | 8 ++++++++ - 3 files changed, 16 insertions(+), 0 deletions(-) - -diff --git a/include/linux/oom.h b/include/linux/oom.h -index 5e3aa83..79a27b4 100644 ---- a/include/linux/oom.h -+++ b/include/linux/oom.h -@@ -72,5 +72,6 @@ extern struct task_struct *find_lock_task_mm(struct task_struct *p); - extern int sysctl_oom_dump_tasks; - extern int sysctl_oom_kill_allocating_task; - extern int sysctl_panic_on_oom; -+extern int sysctl_would_have_oomkilled; - #endif /* __KERNEL__*/ - #endif /* _INCLUDE_LINUX_OOM_H */ -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 5abfa15..a0fed6d 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -1000,6 +1000,13 @@ static struct ctl_table vm_table[] = { - .proc_handler = proc_dointvec, - }, - { -+ .procname = "would_have_oomkilled", -+ .data = &sysctl_would_have_oomkilled, -+ .maxlen = sizeof(sysctl_would_have_oomkilled), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, -+ { - .procname = "overcommit_ratio", - .data = &sysctl_overcommit_ratio, - .maxlen = sizeof(sysctl_overcommit_ratio), -diff --git a/mm/oom_kill.c b/mm/oom_kill.c -index 7dcca55..281ac39 100644 ---- a/mm/oom_kill.c -+++ b/mm/oom_kill.c -@@ -35,6 +35,7 @@ - int sysctl_panic_on_oom; - int sysctl_oom_kill_allocating_task; - int sysctl_oom_dump_tasks = 1; -+int sysctl_would_have_oomkilled; - static DEFINE_SPINLOCK(zone_scan_lock); - - #ifdef CONFIG_NUMA -@@ -477,6 +478,13 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, - } - - task_lock(p); -+ if (sysctl_would_have_oomkilled) { -+ printk(KERN_ERR "%s: would have killed process %d (%s), but continuing instead...\n", -+ __func__, task_pid_nr(p), p->comm); -+ task_unlock(p); -+ return 0; -+ } -+ - pr_err("%s: Kill process %d (%s) score %d or sacrifice child\n", - message, task_pid_nr(p), p->comm, points); - task_unlock(p); --- -1.7.3.2 - diff --git a/linux-2.6-defaults-acpi-video.patch b/linux-2.6-defaults-acpi-video.patch index af883b0d3..b83f4b614 100644 --- a/linux-2.6-defaults-acpi-video.patch +++ b/linux-2.6-defaults-acpi-video.patch @@ -1,13 +1,13 @@ diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c -index d8d7596..a1b7117 100644 +index eaef02a..2029819 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c -@@ -71,7 +71,7 @@ MODULE_AUTHOR("Bruno Ducrot"); +@@ -69,7 +69,7 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); --static int brightness_switch_enabled = 1; -+static int brightness_switch_enabled = 0; +-static bool brightness_switch_enabled = 1; ++static bool brightness_switch_enabled = 0; module_param(brightness_switch_enabled, bool, 0644); - static int acpi_video_bus_add(struct acpi_device *device); + /* diff --git a/linux-2.6-defaults-aspm.patch b/linux-2.6-defaults-aspm.patch deleted file mode 100644 index 49b832d2c..000000000 --- a/linux-2.6-defaults-aspm.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up linux-2.6.30.noarch/drivers/pci/pcie/aspm.c.mjg linux-2.6.30.noarch/drivers/pci/pcie/aspm.c ---- linux-2.6.30.noarch/drivers/pci/pcie/aspm.c.mjg 2009-07-16 22:01:11.000000000 +0100 -+++ linux-2.6.30.noarch/drivers/pci/pcie/aspm.c 2009-07-16 22:01:30.000000000 +0100 -@@ -65,7 +65,7 @@ static LIST_HEAD(link_list); - #define POLICY_DEFAULT 0 /* BIOS default setting */ - #define POLICY_PERFORMANCE 1 /* high performance */ - #define POLICY_POWERSAVE 2 /* high power saving */ --static int aspm_policy; -+static int aspm_policy = POLICY_POWERSAVE; - static const char *policy_str[] = { - [POLICY_DEFAULT] = "default", - [POLICY_PERFORMANCE] = "performance", diff --git a/linux-2.6-e1000-ich9-montevina.patch b/linux-2.6-e1000-ich9-montevina.patch index d45fd5673..ec38a3902 100644 --- a/linux-2.6-e1000-ich9-montevina.patch +++ b/linux-2.6-e1000-ich9-montevina.patch @@ -1,11 +1,22 @@ +From 802e6d8c8477a553a677b23a247d6d2638e01958 Mon Sep 17 00:00:00 2001 +From: Dave Jones +Date: Wed, 26 Oct 2011 13:31:47 -0400 +Subject: [PATCH] e1000e: ich9 montevina + This only showed up in one SDV (Montevina). The PCIE slots don't seem to like network cards, so this is the only hope to get networking working. It's never going upstream, but it's low impact enough to carry just to keep those SDVs working. +--- + drivers/net/ethernet/intel/e1000e/ich8lan.c | 6 ++++++ + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 2 files changed, 7 insertions(+), 0 deletions(-) ---- linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c~ 2010-09-29 17:53:13.000000000 -0400 -+++ linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c 2010-09-29 17:54:00.000000000 -0400 -@@ -424,6 +424,12 @@ static s32 e1000_init_phy_params_ich8lan +diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c +index 6a17c62..0e40975 100644 +--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c ++++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c +@@ -452,6 +452,12 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) /* Verify phy id */ switch (phy->id) { @@ -18,9 +29,11 @@ enough to carry just to keep those SDVs working. case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ---- linux-2.6.35.noarch/drivers/net/e1000e/netdev.c~ 2010-09-29 17:54:07.000000000 -0400 -+++ linux-2.6.35.noarch/drivers/net/e1000e/netdev.c 2010-09-29 17:54:29.000000000 -0400 -@@ -5994,6 +5994,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index a855db1..edac30b 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -6359,6 +6359,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, @@ -28,3 +41,6 @@ enough to carry just to keep those SDVs working. { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, +-- +1.7.6.4 + diff --git a/linux-2.6-enable-more-pci-autosuspend.patch b/linux-2.6-enable-more-pci-autosuspend.patch deleted file mode 100644 index 666ded640..000000000 --- a/linux-2.6-enable-more-pci-autosuspend.patch +++ /dev/null @@ -1,452 +0,0 @@ - drivers/acpi/acpica/aclocal.h | 7 +-- - drivers/acpi/acpica/evgpe.c | 75 +++++++++++++++----------------- - drivers/acpi/acpica/evgpeinit.c | 11 +---- - drivers/acpi/acpica/evgpeutil.c | 5 +- - drivers/acpi/acpica/evxface.c | 23 +++++----- - drivers/acpi/ec.c | 2 +- - drivers/acpi/pci_bind.c | 86 ++++++++++++++++++++++++++++++++++++++ - drivers/acpi/sleep.c | 2 +- - drivers/char/ipmi/ipmi_si_intf.c | 2 +- - include/acpi/acpixf.h | 3 +- - 10 files changed, 143 insertions(+), 73 deletions(-) - -diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h -index 2ceb0c0..3663362 100644 ---- a/drivers/acpi/acpica/aclocal.h -+++ b/drivers/acpi/acpica/aclocal.h -@@ -406,17 +406,16 @@ struct acpi_predefined_data { - * - ****************************************************************************/ - --/* Dispatch info for each GPE -- either a method or handler, cannot be both */ -+/* Dispatch info for each GPE */ - - struct acpi_handler_info { - acpi_event_handler address; /* Address of handler, if any */ - void *context; /* Context to be passed to handler */ -- struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ - u8 orig_flags; /* Original misc info about this GPE */ - u8 orig_enabled; /* Set if the GPE was originally enabled */ - }; - --union acpi_gpe_dispatch_info { -+struct acpi_gpe_dispatch_info { - struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - struct acpi_handler_info *handler; - }; -@@ -426,7 +425,7 @@ union acpi_gpe_dispatch_info { - * NOTE: Important to keep this struct as small as possible. - */ - struct acpi_gpe_event_info { -- union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ -+ struct acpi_gpe_dispatch_info dispatch; - struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ - u8 flags; /* Misc info about this GPE */ - u8 gpe_number; /* This GPE */ -diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c -index f226eac..c4b1c4c 100644 ---- a/drivers/acpi/acpica/evgpe.c -+++ b/drivers/acpi/acpica/evgpe.c -@@ -474,9 +474,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) - * Must check for control method type dispatch one more time to avoid a - * race with ev_gpe_install_handler - */ -- if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == -- ACPI_GPE_DISPATCH_METHOD) { -- -+ if (local_gpe_event_info.flags & ACPI_GPE_DISPATCH_METHOD) { - /* Allocate the evaluation information block */ - - info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); -@@ -575,41 +573,15 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) - } - - /* -- * Dispatch the GPE to either an installed handler, or the control method -- * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke -- * it and do not attempt to run the method. If there is neither a handler -- * nor a method, we disable this GPE to prevent further such pointless -- * events from firing. -+ * Dispatch the GPE to either any installed handler or control -+ * method associated with this GPE (_Lxx or _Exx). We invoke -+ * the method first in case it has side effects that would be -+ * interfered with if the handler has already altered hardware -+ * state. If there is neither a handler nor a method, we -+ * disable this GPE to prevent further such pointless events -+ * from firing. - */ -- switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { -- case ACPI_GPE_DISPATCH_HANDLER: -- -- /* -- * Invoke the installed handler (at interrupt level) -- * Ignore return status for now. -- * TBD: leave GPE disabled on error? -- */ -- (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> -- dispatch. -- handler-> -- context); -- -- /* It is now safe to clear level-triggered events. */ -- -- if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == -- ACPI_GPE_LEVEL_TRIGGERED) { -- status = acpi_hw_clear_gpe(gpe_event_info); -- if (ACPI_FAILURE(status)) { -- ACPI_EXCEPTION((AE_INFO, status, -- "Unable to clear GPE[0x%2X]", -- gpe_number)); -- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); -- } -- } -- break; -- -- case ACPI_GPE_DISPATCH_METHOD: -- -+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) { - /* - * Disable the GPE, so it doesn't keep firing before the method has a - * chance to run (it runs asynchronously with interrupts enabled). -@@ -634,10 +606,34 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) - "Unable to queue handler for GPE[0x%2X] - event disabled", - gpe_number)); - } -- break; -+ } - -- default: -+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) { -+ /* -+ * Invoke the installed handler (at interrupt level) -+ * Ignore return status for now. -+ * TBD: leave GPE disabled on error? -+ */ -+ (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> -+ dispatch. -+ handler-> -+ context); - -+ /* It is now safe to clear level-triggered events. */ -+ -+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == -+ ACPI_GPE_LEVEL_TRIGGERED) { -+ status = acpi_hw_clear_gpe(gpe_event_info); -+ if (ACPI_FAILURE(status)) { -+ ACPI_EXCEPTION((AE_INFO, status, -+ "Unable to clear GPE[0x%2X]", -+ gpe_number)); -+ return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); -+ } -+ } -+ } -+ -+ if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) { - /* - * No handler or method to run! - * 03/2010: This case should no longer be possible. We will not allow -@@ -658,7 +654,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) - gpe_number)); - return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); - } -- break; - } - - return_UINT32(ACPI_INTERRUPT_HANDLED); -diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c -index 2c7def9..9915b52 100644 ---- a/drivers/acpi/acpica/evgpeinit.c -+++ b/drivers/acpi/acpica/evgpeinit.c -@@ -386,16 +386,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, - return_ACPI_STATUS(AE_OK); - } - -- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == -- ACPI_GPE_DISPATCH_HANDLER) { -- -- /* If there is already a handler, ignore this GPE method */ -- -- return_ACPI_STATUS(AE_OK); -- } -- -- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == -- ACPI_GPE_DISPATCH_METHOD) { -+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) { - /* - * If there is already a method, ignore this method. But check - * for a type mismatch (if both the _Lxx AND _Exx exist) -diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c -index 19a0e51..434ad1b 100644 ---- a/drivers/acpi/acpica/evgpeutil.c -+++ b/drivers/acpi/acpica/evgpeutil.c -@@ -323,12 +323,11 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - ACPI_GPE_REGISTER_WIDTH) - + j]; - -- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == -- ACPI_GPE_DISPATCH_HANDLER) { -+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) { - ACPI_FREE(gpe_event_info->dispatch.handler); - gpe_event_info->dispatch.handler = NULL; - gpe_event_info->flags &= -- ~ACPI_GPE_DISPATCH_MASK; -+ ~ACPI_GPE_DISPATCH_HANDLER; - } - } - } -diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c -index 36af222..b097136 100644 ---- a/drivers/acpi/acpica/evxface.c -+++ b/drivers/acpi/acpica/evxface.c -@@ -662,6 +662,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler) - * edge- or level-triggered interrupt. - * Address - Address of the handler - * Context - Value passed to the handler on each GPE -+ * keep_method - Whether the existing method should be -+ * displaced or kept - * - * RETURN: Status - * -@@ -671,7 +673,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler) - acpi_status - acpi_install_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, -- u32 type, acpi_event_handler address, void *context) -+ u32 type, acpi_event_handler address, void *context, -+ bool keep_method) - { - struct acpi_gpe_event_info *gpe_event_info; - struct acpi_handler_info *handler; -@@ -711,8 +714,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, - - /* Make sure that there isn't a handler there already */ - -- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == -- ACPI_GPE_DISPATCH_HANDLER) { -+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) { - status = AE_ALREADY_EXISTS; - goto free_and_exit; - } -@@ -721,7 +723,6 @@ acpi_install_gpe_handler(acpi_handle gpe_device, - - handler->address = address; - handler->context = context; -- handler->method_node = gpe_event_info->dispatch.method_node; - handler->orig_flags = gpe_event_info->flags & - (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - -@@ -732,7 +733,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, - */ - - if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD) -- && gpe_event_info->runtime_count) { -+ && gpe_event_info->runtime_count && !keep_method) { - handler->orig_enabled = 1; - (void)acpi_raw_disable_gpe(gpe_event_info); - } -@@ -741,10 +742,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, - - gpe_event_info->dispatch.handler = handler; - -- /* Setup up dispatch flags to indicate handler (vs. method) */ -+ if (!keep_method) -+ gpe_event_info->flags &= -+ ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - -- gpe_event_info->flags &= -- ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); - - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); -@@ -813,8 +814,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, - - /* Make sure that a handler is indeed installed */ - -- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != -- ACPI_GPE_DISPATCH_HANDLER) { -+ if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER)) { - status = AE_NOT_EXIST; - goto unlock_and_exit; - } -@@ -830,9 +830,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, - - handler = gpe_event_info->dispatch.handler; - -- /* Restore Method node (if any), set dispatch flags */ -+ /* Set dispatch flags */ - -- gpe_event_info->dispatch.method_node = handler->method_node; - gpe_event_info->flags &= - ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - gpe_event_info->flags |= handler->orig_flags; -diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c -index 372ff80..9a39f82 100644 ---- a/drivers/acpi/ec.c -+++ b/drivers/acpi/ec.c -@@ -740,7 +740,7 @@ static int ec_install_handlers(struct acpi_ec *ec) - return 0; - status = acpi_install_gpe_handler(NULL, ec->gpe, - ACPI_GPE_EDGE_TRIGGERED, -- &acpi_ec_gpe_handler, ec); -+ &acpi_ec_gpe_handler, ec, false); - if (ACPI_FAILURE(status)) - return -ENODEV; - -diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c -index 2ef0409..8b3cc6a 100644 ---- a/drivers/acpi/pci_bind.c -+++ b/drivers/acpi/pci_bind.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -35,6 +36,43 @@ - #define _COMPONENT ACPI_PCI_COMPONENT - ACPI_MODULE_NAME("pci_bind"); - -+static LIST_HEAD(acpi_pci_gpe_devs); -+ -+struct pci_gpe_dev { -+ struct list_head node; -+ struct pci_dev *dev; -+ acpi_handle gpe_device; -+ int gpe_number; -+ struct work_struct work; -+}; -+ -+static void acpi_pci_wake_handler_work(struct work_struct *work) -+{ -+ struct pci_gpe_dev *gpe_dev = container_of(work, struct pci_gpe_dev, -+ work); -+ -+ pci_check_pme_status(gpe_dev->dev); -+ pm_runtime_resume(&gpe_dev->dev->dev); -+ pci_wakeup_event(gpe_dev->dev); -+ if (gpe_dev->dev->subordinate) -+ pci_pme_wakeup_bus(gpe_dev->dev->subordinate); -+} -+ -+static u32 acpi_pci_wake_handler(void *data) -+{ -+ long gpe_number = (long) data; -+ struct pci_gpe_dev *gpe_dev; -+ -+ list_for_each_entry(gpe_dev, &acpi_pci_gpe_devs, node) { -+ if (gpe_number != gpe_dev->gpe_number) -+ continue; -+ -+ schedule_work(&gpe_dev->work); -+ } -+ -+ return ACPI_INTERRUPT_HANDLED; -+} -+ - static int acpi_pci_unbind(struct acpi_device *device) - { - struct pci_dev *dev; -@@ -43,6 +81,30 @@ static int acpi_pci_unbind(struct acpi_device *device) - if (!dev) - goto out; - -+ if (device->wakeup.flags.valid) { -+ struct pci_gpe_dev *gpe_dev; -+ struct pci_gpe_dev *tmp; -+ int gpe_count = 0; -+ int gpe_number = device->wakeup.gpe_number; -+ acpi_handle gpe_device = device->wakeup.gpe_device; -+ -+ list_for_each_entry_safe(gpe_dev, tmp, &acpi_pci_gpe_devs, node) { -+ if (gpe_dev->dev == dev) { -+ flush_work(&gpe_dev->work); -+ list_del(&gpe_dev->node); -+ kfree(gpe_dev); -+ } else if (gpe_dev->gpe_number == gpe_number && -+ gpe_dev->gpe_device == gpe_device) { -+ gpe_count++; -+ } -+ } -+ -+ if (gpe_count == 0) { -+ acpi_remove_gpe_handler(gpe_device, gpe_number, -+ &acpi_pci_wake_handler); -+ } -+ } -+ - device_set_run_wake(&dev->dev, false); - pci_acpi_remove_pm_notifier(device); - -@@ -71,6 +133,30 @@ static int acpi_pci_bind(struct acpi_device *device) - return 0; - - pci_acpi_add_pm_notifier(device, dev); -+ if (device->wakeup.flags.valid) { -+ struct pci_gpe_dev *gpe_dev; -+ acpi_handle gpe_device = device->wakeup.gpe_device; -+ long gpe_number = device->wakeup.gpe_number; -+ -+ gpe_dev = kmalloc(sizeof(struct pci_gpe_dev), GFP_KERNEL); -+ if (gpe_dev) { -+ gpe_dev->dev = dev; -+ gpe_dev->gpe_device = gpe_device; -+ gpe_dev->gpe_number = gpe_number; -+ INIT_WORK(&gpe_dev->work, acpi_pci_wake_handler_work); -+ -+ acpi_install_gpe_handler(gpe_device, gpe_number, -+ ACPI_GPE_LEVEL_TRIGGERED, -+ &acpi_pci_wake_handler, -+ (void *)gpe_number, -+ true); -+ acpi_gpe_can_wake(device->wakeup.gpe_device, -+ device->wakeup.gpe_number); -+ device->wakeup.flags.run_wake = 1; -+ list_add_tail(&gpe_dev->node, &acpi_pci_gpe_devs); -+ } -+ } -+ - if (device->wakeup.flags.run_wake) - device_set_run_wake(&dev->dev, true); - -diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c -index 721d93b..b0ddef6 100644 ---- a/drivers/acpi/sleep.c -+++ b/drivers/acpi/sleep.c -@@ -643,7 +643,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) - if (acpi_target_sleep_state != ACPI_STATE_S0 || - status != AE_NOT_FOUND) - d_max = d_min; -- } else if (d_max < d_min) { -+ } else if (ACPI_SUCCESS(status) && d_max < d_min) { - /* Warn the user of the broken DSDT */ - printk(KERN_WARNING "ACPI: Wrong value from %s\n", - acpi_method); -diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c -index 035da9e..62a48b2 100644 ---- a/drivers/char/ipmi/ipmi_si_intf.c -+++ b/drivers/char/ipmi/ipmi_si_intf.c -@@ -1970,7 +1970,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info) - info->irq, - ACPI_GPE_LEVEL_TRIGGERED, - &ipmi_acpi_gpe, -- info); -+ info, false); - if (status != AE_OK) { - dev_warn(info->dev, "%s unable to claim ACPI GPE %d," - " running polled\n", DEVICE_NAME, info->irq); -diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h -index 53b7cfd..740eb7e 100644 ---- a/include/acpi/acpixf.h -+++ b/include/acpi/acpixf.h -@@ -258,7 +258,8 @@ acpi_remove_address_space_handler(acpi_handle device, - acpi_status - acpi_install_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, -- u32 type, acpi_event_handler address, void *context); -+ u32 type, acpi_event_handler address, void *context, -+ bool keep_method); - - acpi_status - acpi_remove_gpe_handler(acpi_handle gpe_device, diff --git a/linux-2.6-i386-nx-emulation.patch b/linux-2.6-i386-nx-emulation.patch index 856b9b95a..d97d52999 100644 --- a/linux-2.6-i386-nx-emulation.patch +++ b/linux-2.6-i386-nx-emulation.patch @@ -1,3 +1,5 @@ +diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h +index 41935fa..6e9259b 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -5,6 +5,7 @@ @@ -44,6 +46,8 @@ +#endif /* CONFIG_X86_32 */ + #endif /* _ASM_X86_DESC_H */ +diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h +index 5f55e69..aba94f0 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -7,6 +7,9 @@ @@ -68,9 +72,11 @@ } mm_context_t; #ifdef CONFIG_SMP +diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h +index a7d2db9..cc4ad60 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h -@@ -289,6 +289,12 @@ static inline void set_ldt(const void *addr, unsigned entries) +@@ -298,6 +298,12 @@ static inline void set_ldt(const void *addr, unsigned entries) { PVOP_VCALL2(pv_cpu_ops.set_ldt, addr, entries); } @@ -83,9 +89,11 @@ static inline void store_gdt(struct desc_ptr *dtr) { PVOP_VCALL1(pv_cpu_ops.store_gdt, dtr); +diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h +index 8e8b9a4..cca421e 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h -@@ -118,6 +118,9 @@ struct pv_cpu_ops { +@@ -125,6 +125,9 @@ struct pv_cpu_ops { void (*store_gdt)(struct desc_ptr *); void (*store_idt)(struct desc_ptr *); void (*set_ldt)(const void *desc, unsigned entries); @@ -95,9 +103,11 @@ unsigned long (*store_tr)(void); void (*load_tls)(struct thread_struct *t, unsigned int cpu); #ifdef CONFIG_X86_64 +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index aa003b1..c094152 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c -@@ -802,6 +802,22 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) +@@ -844,6 +844,22 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) /* Filter out anything that depends on CPUID levels we don't have */ filter_cpuid_features(c, true); @@ -120,9 +130,11 @@ /* If the model name is still unset, do table lookup. */ if (!c->x86_model_id[0]) { const char *p; +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index d90272e..cc594fc 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c -@@ -345,6 +345,9 @@ struct pv_cpu_ops pv_cpu_ops = { +@@ -358,6 +358,9 @@ struct pv_cpu_ops pv_cpu_ops = { .read_tscp = native_read_tscp, .load_tr_desc = native_load_tr_desc, .set_ldt = native_set_ldt, @@ -132,9 +144,11 @@ .load_gdt = native_load_gdt, .load_idt = native_load_idt, .store_gdt = native_store_gdt, +diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c +index 8598296..641ae48 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c -@@ -243,7 +243,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, +@@ -247,7 +247,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) { @@ -145,7 +159,7 @@ regs->fs = 0; regs->ds = __USER_DS; regs->es = __USER_DS; -@@ -252,6 +255,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) +@@ -255,6 +258,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) regs->cs = __USER_CS; regs->ip = new_ip; regs->sp = new_sp; @@ -157,17 +171,17 @@ /* * Free the old FP and other extended state */ -@@ -311,6 +319,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) - if (preload_fpu) - prefetch(next->fpu.state); +@@ -320,6 +328,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + */ + lazy_save_gs(prev->gs); + if (next_p->mm) + load_user_cs_desc(cpu, next_p->mm); + /* - * Reload esp0. + * Load the per-thread Thread-Local Storage descriptor. */ -@@ -404,3 +415,40 @@ unsigned long get_wchan(struct task_struct *p) +@@ -390,3 +401,40 @@ unsigned long get_wchan(struct task_struct *p) return 0; } @@ -208,9 +222,11 @@ + mm->context.exec_limit = 0; + set_user_cs(&mm->context.user_cs, 0); +} +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index 31d9d0f..f7c210d 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c -@@ -109,6 +109,78 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) +@@ -107,6 +107,78 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) dec_preempt_count(); } @@ -249,7 +265,7 @@ + for (vma = current->mm->mmap; vma; vma = vma->vm_next) + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; -+ vma = get_gate_vma(current); ++ vma = get_gate_vma(current->mm); + if (vma && (vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; + spin_unlock(¤t->mm->page_table_lock); @@ -289,7 +305,7 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, long error_code, siginfo_t *info) -@@ -265,6 +337,29 @@ do_general_protection(struct pt_regs *regs, long error_code) +@@ -263,6 +335,29 @@ do_general_protection(struct pt_regs *regs, long error_code) if (!user_mode(regs)) goto gp_in_kernel; @@ -319,7 +335,7 @@ tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; -@@ -792,19 +887,37 @@ do_device_not_available(struct pt_regs *regs, long error_code) +@@ -649,19 +744,37 @@ do_device_not_available(struct pt_regs *regs, long error_code) } #ifdef CONFIG_X86_32 @@ -366,6 +382,8 @@ } #endif +diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c +index 410531d..eb040ad 100644 --- a/arch/x86/mm/setup_nx.c +++ b/arch/x86/mm/setup_nx.c @@ -1,3 +1,4 @@ @@ -373,16 +391,16 @@ #include #include #include -@@ -6,7 +6,7 @@ +@@ -5,7 +6,7 @@ #include #include - + -static int disable_nx __cpuinitdata; +int disable_nx __cpuinitdata; - + /* * noexec = on|off -@@ -40,6 +42,10 @@ void __cpuinit x86_configure_nx(void) +@@ -40,6 +41,10 @@ void __cpuinit x86_configure_nx(void) void __init x86_report_nx(void) { if (!cpu_has_nx) { @@ -393,9 +411,11 @@ printk(KERN_NOTICE "Notice: NX (Execute Disable) protection " "missing in CPU!\n"); } else { +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index d6c0418..c15b765 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c -@@ -6,6 +6,7 @@ +@@ -7,6 +7,7 @@ #include #include @@ -403,7 +423,7 @@ #include #include #include -@@ -131,6 +132,12 @@ void smp_invalidate_interrupt(struct pt_regs *regs) +@@ -134,6 +135,12 @@ void smp_invalidate_interrupt(struct pt_regs *regs) union smp_flush_state *f; cpu = smp_processor_id(); @@ -416,9 +436,11 @@ /* * orig_rax contains the negated interrupt vector. * Use that to determine where the sender put the data. +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 1f92865..b8f4319 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c -@@ -335,6 +335,24 @@ static void xen_set_ldt(const void *addr, unsigned entries) +@@ -354,6 +354,24 @@ static void xen_set_ldt(const void *addr, unsigned entries) xen_mc_issue(PARAVIRT_LAZY_CPU); } @@ -443,7 +465,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr) { unsigned long va = dtr->address; -@@ -961,6 +979,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { +@@ -994,6 +1012,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .load_tr_desc = paravirt_nop, .set_ldt = xen_set_ldt, @@ -453,9 +475,11 @@ .load_gdt = xen_load_gdt, .load_idt = xen_load_idt, .load_tls = xen_load_tls, +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index 21ac5ee..3f26963 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c -@@ -717,6 +722,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) +@@ -711,6 +711,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (retval) goto out_free_dentry; @@ -471,9 +495,11 @@ /* OK, This is the point of no return */ current->flags &= ~PF_FORKNOEXEC; current->mm->def_flags = def_flags; +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 1c4f3e9..52011a7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h -@@ -101,6 +101,9 @@ struct bio_list; +@@ -102,6 +102,9 @@ struct fs_struct; struct perf_event_context; struct blk_plug; @@ -483,9 +509,11 @@ /* * List of flags we want to share for kernel threads, * if only because they are not used by them anyway. ---- b/mm/mmap.c +diff --git a/mm/mmap.c b/mm/mmap.c +index eae90af..f4de6c0 100644 +--- a/mm/mmap.c +++ b/mm/mmap.c -@@ -44,6 +45,18 @@ +@@ -46,6 +46,18 @@ #define arch_rebalance_pgtables(addr, len) (addr) #endif @@ -504,7 +532,7 @@ static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end); -@@ -432,6 +432,8 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -424,6 +436,8 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node **rb_link, struct rb_node *rb_parent) { @@ -513,7 +541,7 @@ __vma_link_list(mm, vma, prev, rb_parent); __vma_link_rb(mm, vma, rb_link, rb_parent); } -@@ -489,6 +504,8 @@ +@@ -478,6 +492,8 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma, rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) mm->mmap_cache = prev; @@ -522,7 +550,7 @@ } /* -@@ -790,6 +807,8 @@ +@@ -794,6 +810,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, } else /* cases 2, 5, 7 */ err = vma_adjust(prev, prev->vm_start, end, prev->vm_pgoff, NULL); @@ -530,8 +558,8 @@ + arch_add_exec_range(mm, prev->vm_end); if (err) return NULL; - return prev; -@@ -1966,10 +2075,14 @@ + khugepaged_enter_vma_merge(prev); +@@ -1972,10 +1990,14 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); @@ -548,7 +576,7 @@ err = vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new); /* Success. */ -@@ -2254,6 +2367,7 @@ +@@ -2263,6 +2285,7 @@ void exit_mmap(struct mm_struct *mm) free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0); tlb_finish_mmu(&tlb, 0, end); @@ -556,6 +584,8 @@ /* * Walk the list again, actually closing and freeing it, +diff --git a/mm/mprotect.c b/mm/mprotect.c +index 5a688a2..128d996 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -25,9 +25,14 @@ @@ -573,7 +603,7 @@ #ifndef pgprot_modify static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) { -@@ -138,7 +143,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, +@@ -148,7 +153,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, struct mm_struct *mm = vma->vm_mm; unsigned long oldflags = vma->vm_flags; long nrpages = (end - start) >> PAGE_SHIFT; @@ -582,7 +612,7 @@ pgoff_t pgoff; int error; int dirty_accountable = 0; -@@ -203,6 +208,9 @@ success: +@@ -213,6 +218,9 @@ success: dirty_accountable = 1; } @@ -592,25 +622,3 @@ mmu_notifier_invalidate_range_start(mm, start, end); if (is_vm_hugetlb_page(vma)) hugetlb_change_protection(vma, start, end, vma->vm_page_prot); -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 57d1868..29c0c35 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -669,6 +669,16 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - unsigned long range_end = mm->brk + 0x02000000; -- return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -+ unsigned long bump = 0; -+#ifdef CONFIG_X86_32 -+ /* in the case of NX emulation, shove the brk segment way out of the -+ way of the exec randomization area, since it can collide with -+ future allocations if not. */ -+ if ( (mm->get_unmapped_exec_area == arch_get_unmapped_exec_area) && -+ (mm->brk < 0x08000000) ) { -+ bump = (TASK_SIZE/6); -+ } -+#endif -+ return bump + (randomize_range(mm->brk, range_end, 0) ? : mm->brk); - } - diff --git a/linux-2.6-input-kill-stupid-messages.patch b/linux-2.6-input-kill-stupid-messages.patch index cc1dd7470..ff7023f51 100644 --- a/linux-2.6-input-kill-stupid-messages.patch +++ b/linux-2.6-input-kill-stupid-messages.patch @@ -1,32 +1,20 @@ -From b2c6d55b2351152696aafb8c9bf3ec8968acf77c Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 29 Mar 2010 23:59:58 -0400 -Subject: linux-2.6-input-kill-stupid-messages - ---- - drivers/input/keyboard/atkbd.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c -index d358ef8..38db098 100644 +index add5ffd..5eb2f03 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c -@@ -425,11 +426,15 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, +@@ -430,11 +430,15 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, goto out; case ATKBD_RET_ACK: case ATKBD_RET_NAK: -+#if 0 ++# if 0 + /* Quite a few key switchers and other tools trigger this + * and it confuses people who can do nothing about it */ if (printk_ratelimit()) dev_warn(&serio->dev, "Spurious %s on %s. " - "Some program might be trying access hardware directly.\n", + "Some program might be trying to access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); +#endif goto out; case ATKBD_RET_ERR: atkbd->err_count++; --- -1.7.0.1 - diff --git a/linux-2.6-intel-iommu-igfx.patch b/linux-2.6-intel-iommu-igfx.patch index b2f8f19e3..3a45abaec 100644 --- a/linux-2.6-intel-iommu-igfx.patch +++ b/linux-2.6-intel-iommu-igfx.patch @@ -1,6 +1,7 @@ -Subject: [PATCH] [intel_iommu] Default to igfx_off +From 602e1f209dd983e40d989e871cd253e8187899b8 Mon Sep 17 00:00:00 2001 From: drago01 -To: fedora-kernel-list +Date: Wed, 26 Oct 2011 13:37:27 -0400 +Subject: [PATCH] Default to igfx_off This option seems to causes way to many issues, it is being investigated by Intel's chipset team for months now and @@ -16,14 +17,14 @@ Signed-off-by: Adel Gadllah Reviewed-by: Adam Jackson --- Documentation/kernel-parameters.txt | 11 +++++------ - drivers/pci/intel-iommu.c | 9 +++++---- + drivers/iommu/intel-iommu.c | 9 +++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index e7848a0..9914485 100644 +index 81c287f..ee5693b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt -@@ -992,12 +992,11 @@ and is between 256 and 4096 characters. It is defined in the file +@@ -1014,12 +1014,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Enable intel iommu driver. off Disable intel iommu driver. @@ -40,22 +41,22 @@ index e7848a0..9914485 100644 + mapped as normal device. forcedac [x86_64] With this option iommu will not optimize to look - for io virtual address below 32 bit forcing dual -diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c -index 4173125..8f36786 100644 + for io virtual address below 32-bit forcing dual +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index bdc447f..240db6b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c -@@ -340,7 +340,8 @@ int dmar_disabled = 0; - int dmar_disabled = 1; - #endif /*CONFIG_DMAR_DEFAULT_ON*/ - +@@ -408,7 +408,8 @@ int dmar_disabled = 1; + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + -static int dmar_map_gfx = 1; +/* disabled by default; causes way too many issues */ +static int dmar_map_gfx = 0; static int dmar_forcedac; static int intel_iommu_strict; - -@@ -361,10 +362,10 @@ static int __init intel_iommu_setup(char *str) + static int intel_iommu_superpage = 1; +@@ -433,10 +434,10 @@ static int __init intel_iommu_setup(char *str) } else if (!strncmp(str, "off", 3)) { dmar_disabled = 1; printk(KERN_INFO "Intel-IOMMU: disabled\n"); @@ -70,9 +71,5 @@ index 4173125..8f36786 100644 printk(KERN_INFO "Intel-IOMMU: Forcing DAC for PCI devices\n"); -- -1.6.6.1 -_______________________________________________ -kernel mailing list -kernel@lists.fedoraproject.org -https://admin.fedoraproject.org/mailman/listinfo/kernel +1.7.7.4 diff --git a/linux-2.6-makefile-after_link.patch b/linux-2.6-makefile-after_link.patch index c2541b1d8..b520b1942 100644 --- a/linux-2.6-makefile-after_link.patch +++ b/linux-2.6-makefile-after_link.patch @@ -1,4 +1,4 @@ -From f072f7db2194c8255c003d985b61ad2f97ebbee0 Mon Sep 17 00:00:00 2001 +From b707aea6a4947c3806ced2c23e889943a0f36876 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 6 Oct 2008 23:03:03 -0700 Subject: [PATCH] kbuild: AFTER_LINK @@ -7,24 +7,9 @@ If the make variable AFTER_LINK is set, it is a command line to run after each final link. This includes vmlinux itself and vDSO images. Signed-off-by: Roland McGrath ---- -diff --git a/Makefile b/Makefile -index f908acc..960ff6f 100644 ---- a/Makefile -+++ b/Makefile -@@ -746,6 +746,10 @@ quiet_cmd_vmlinux__ ?= LD $@ - --start-group $(vmlinux-main) --end-group \ - $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^) - -+ifdef AFTER_LINK -+cmd_vmlinux__ += ; $(AFTER_LINK) -+endif -+ - # Generate new vmlinux version - quiet_cmd_vmlinux_version = GEN .version - cmd_vmlinux_version = set -e; \ + diff --git a/arch/powerpc/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile -index 51ead52..ad21273 100644 +index 9a7946c..28d6765 100644 --- a/arch/powerpc/kernel/vdso32/Makefile +++ b/arch/powerpc/kernel/vdso32/Makefile @@ -41,7 +41,8 @@ $(obj-vdso32): %.o: %.S @@ -38,7 +23,7 @@ index 51ead52..ad21273 100644 cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $< diff --git a/arch/powerpc/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile -index 79da65d..f11c21b 100644 +index 8c500d8..d27737b 100644 --- a/arch/powerpc/kernel/vdso64/Makefile +++ b/arch/powerpc/kernel/vdso64/Makefile @@ -36,7 +36,8 @@ $(obj-vdso64): %.o: %.S @@ -51,11 +36,39 @@ index 79da65d..f11c21b 100644 quiet_cmd_vdso64as = VDSO64A $@ cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< +diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile +index 8ad2b34..e153572 100644 +--- a/arch/s390/kernel/vdso32/Makefile ++++ b/arch/s390/kernel/vdso32/Makefile +@@ -43,7 +43,8 @@ $(obj-vdso32): %.o: %.S + + # actual build commands + quiet_cmd_vdso32ld = VDSO32L $@ +- cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ ++ cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ \ ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) + quiet_cmd_vdso32as = VDSO32A $@ + cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $< + +diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile +index 2a8ddfd..452ca53 100644 +--- a/arch/s390/kernel/vdso64/Makefile ++++ b/arch/s390/kernel/vdso64/Makefile +@@ -43,7 +43,8 @@ $(obj-vdso64): %.o: %.S + + # actual build commands + quiet_cmd_vdso64ld = VDSO64L $@ +- cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ ++ cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ \ ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) + quiet_cmd_vdso64as = VDSO64A $@ + cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< + diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile -index 4a2afa1..12ad9f7 100644 +index fd14be1..1f3eb19 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile -@@ -120,8 +120,9 @@ $(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE +@@ -178,8 +178,9 @@ $(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE quiet_cmd_vdso = VDSO $@ cmd_vdso = $(CC) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ @@ -67,32 +80,21 @@ index 4a2afa1..12ad9f7 100644 VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) GCOV_PROFILE := n +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index cd9c6c6..3edf048 100644 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -65,6 +65,10 @@ vmlinux_link() + -lutil ${1} + rm -f linux + fi ++ if [ -n "${AFTER_LINK}" ]; then ++ /usr/lib/rpm/debugedit -b ${RPM_BUILD_DIR} -d /usr/src/debug -i ${2} \ ++ > ${2}.id ++ fi + } + + +-- +1.7.7.6 -diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile -index d13e875..28a3e1ad 100644 ---- a/arch/s390/kernel/vdso32/Makefile -+++ b/arch/s390/kernel/vdso32/Makefile -@@ -40,7 +40,8 @@ $(obj-vdso32): %.o: %.S - - # actual build commands - quiet_cmd_vdso32ld = VDSO32L $@ -- cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ -+ cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ \ -+ $(if $(AFTER_LINK),; $(AFTER_LINK)) - quiet_cmd_vdso32as = VDSO32A $@ - cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $< - -diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile -index 449352d..e90e656 100644 ---- a/arch/s390/kernel/vdso64/Makefile -+++ b/arch/s390/kernel/vdso64/Makefile -@@ -40,7 +40,8 @@ $(obj-vdso64): %.o: %.S - - # actual build commands - quiet_cmd_vdso64ld = VDSO64L $@ -- cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ -+ cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ \ -+ $(if $(AFTER_LINK),; $(AFTER_LINK)) - quiet_cmd_vdso64as = VDSO64A $@ - cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< - diff --git a/linux-2.6-serial-460800.patch b/linux-2.6-serial-460800.patch index 9aa392c9e..979b248d5 100644 --- a/linux-2.6-serial-460800.patch +++ b/linux-2.6-serial-460800.patch @@ -1,7 +1,7 @@ diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2209620..659c1bb 100644 ---- a/drivers/tty/serial/8250.c -+++ b/drivers/tty/serial/8250.c +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c @@ -7,6 +7,9 @@ * * Copyright (C) 2001 Russell King. diff --git a/linux-2.6-usb-pci-autosuspend.patch b/linux-2.6-usb-pci-autosuspend.patch deleted file mode 100644 index 610a7654d..000000000 --- a/linux-2.6-usb-pci-autosuspend.patch +++ /dev/null @@ -1,22 +0,0 @@ -commit 15d89120d03116adbbf3226a85fbd2fff0b12576 -Author: Matthew Garrett -Date: Fri Sep 17 11:09:12 2010 -0400 - - Enable USB PCI autosuspend by default - -diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c -index c3f9854..3c020e6 100644 ---- a/drivers/usb/core/hcd-pci.c -+++ b/drivers/usb/core/hcd-pci.c -@@ -248,8 +248,10 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) - goto err4; - set_hs_companion(dev, hcd); - -- if (pci_dev_run_wake(dev)) -+ if (pci_dev_run_wake(dev)) { - pm_runtime_put_noidle(&dev->dev); -+ pm_runtime_allow(&dev->dev); -+ } - return retval; - - err4: diff --git a/linux-2.6-v4l-dvb-fixes.patch b/linux-2.6-v4l-dvb-fixes.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/linux-2.6-v4l-dvb-update.patch b/linux-2.6-v4l-dvb-update.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/linux-2.6.29-sparc-IOC_TYPECHECK.patch b/linux-2.6.29-sparc-IOC_TYPECHECK.patch deleted file mode 100644 index d73c30adc..000000000 --- a/linux-2.6.29-sparc-IOC_TYPECHECK.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -up vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h.BAD vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h ---- vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h.BAD 2009-03-09 17:01:32.000000000 -0400 -+++ vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h 2009-03-09 16:52:27.000000000 -0400 -@@ -41,6 +41,17 @@ - ((nr) << _IOC_NRSHIFT) | \ - ((size) << _IOC_SIZESHIFT)) - -+#ifdef __KERNEL__ -+/* provoke compile error for invalid uses of size argument */ -+extern unsigned int __invalid_size_argument_for_IOC; -+#define _IOC_TYPECHECK(t) \ -+ ((sizeof(t) == sizeof(t[1]) && \ -+ sizeof(t) < (1 << _IOC_SIZEBITS)) ? \ -+ sizeof(t) : __invalid_size_argument_for_IOC) -+#else -+#define _IOC_TYPECHECK(t) (sizeof(t)) -+#endif -+ - #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) - #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) - #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) diff --git a/linux-2.6.30-no-pcspkr-modalias.patch b/linux-2.6.30-no-pcspkr-modalias.patch index e210f4625..439269cef 100644 --- a/linux-2.6.30-no-pcspkr-modalias.patch +++ b/linux-2.6.30-no-pcspkr-modalias.patch @@ -1,7 +1,8 @@ -diff -up linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx linux-2.6.30.noarch/drivers/input/misc/pcspkr.c ---- linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx 2009-07-28 16:54:44.000000000 -0400 -+++ linux-2.6.30.noarch/drivers/input/misc/pcspkr.c 2009-07-28 16:59:36.000000000 -0400 -@@ -23,7 +23,6 @@ +diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c +index 34f4d2e..3e40c70 100644 +--- a/drivers/input/misc/pcspkr.c ++++ b/drivers/input/misc/pcspkr.c +@@ -24,7 +24,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); diff --git a/lis3-improve-handling-of-null-rate.patch b/lis3-improve-handling-of-null-rate.patch new file mode 100644 index 000000000..98512564a --- /dev/null +++ b/lis3-improve-handling-of-null-rate.patch @@ -0,0 +1,79 @@ +>From 56fb161a9ca0129f8e266e4dbe79346552ff8089 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=89ric=20Piel?= +Date: Thu, 3 Nov 2011 16:22:40 +0100 +Subject: [PATCH] lis3: Improve handling of null rate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When obtaining a rate of 0, we would disable the device supposely +because it seems to behave incorectly. It actually only comes from the +fact that the device is off and on lis3dc it's reflected in the rate. +So handle this nicely by just waiting a safe time, and then using the +device as normally. + +Signed-off-by: ??ric Piel +--- + drivers/misc/lis3lv02d/lis3lv02d.c | 16 ++++++++-------- + 1 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c +index 35c67e0..42dce2a 100644 +--- a/drivers/misc/lis3lv02d/lis3lv02d.c ++++ b/drivers/misc/lis3lv02d/lis3lv02d.c +@@ -188,7 +188,8 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) + /* conversion btw sampling rate and the register values */ + static int lis3_12_rates[4] = {40, 160, 640, 2560}; + static int lis3_8_rates[2] = {100, 400}; +-static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; ++/* LIS3DC: 0 = power off, above 9 = undefined */ ++static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000, -1, -1, -1, -1, -1, -1}; + + /* ODR is Output Data Rate */ + static int lis3lv02d_get_odr(struct lis3lv02d *lis3) +@@ -202,12 +203,11 @@ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) + return lis3->odrs[(ctrl >> shift)]; + } + +-static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3) ++static int lis3lv02d_wait_pwron(struct lis3lv02d *lis3) + { + int div = lis3lv02d_get_odr(lis3); +- +- if (WARN_ONCE(div == 0, "device returned spurious data")) +- return -ENXIO; ++ if (div <= 0) ++ div = 1; /* maximum delay */ + + /* LIS3 power on delay is quite long */ + msleep(lis3->pwron_delay / div); +@@ -274,7 +274,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) + + lis3->read(lis3, ctlreg, ®); + lis3->write(lis3, ctlreg, (reg | selftest)); +- ret = lis3lv02d_get_pwron_wait(lis3); ++ ret = lis3lv02d_wait_pwron(lis3); + if (ret) + goto fail; + +@@ -285,7 +285,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) + + /* back to normal settings */ + lis3->write(lis3, ctlreg, reg); +- ret = lis3lv02d_get_pwron_wait(lis3); ++ ret = lis3lv02d_wait_pwron(lis3); + if (ret) + goto fail; + +@@ -397,7 +397,7 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3) + lis3->write(lis3, CTRL_REG2, reg); + } + +- err = lis3lv02d_get_pwron_wait(lis3); ++ err = lis3lv02d_wait_pwron(lis3); + if (err) + return err; + +-- +1.7.7.1 + diff --git a/mac80211-fix-ibss-scanning.patch b/mac80211-fix-ibss-scanning.patch new file mode 100644 index 000000000..c2bc698a0 --- /dev/null +++ b/mac80211-fix-ibss-scanning.patch @@ -0,0 +1,132 @@ +Do not scan on no-IBSS and disabled channels in IBSS mode. Doing this +can trigger Microcode errors on iwlwifi and iwlegacy drivers. + +Also rename ieee80211_request_internal_scan() function since it is only +used in IBSS mode and simplify calling it from ieee80211_sta_find_ibss(). + +This patch should address: +https://bugzilla.redhat.com/show_bug.cgi?id=883414 +https://bugzilla.kernel.org/show_bug.cgi?id=49411 + +Reported-by: Jesse Kahtava +Reported-by: Mikko Rapeli +Cc: stable@vger.kernel.org +Signed-off-by: Stanislaw Gruszka +--- + net/mac80211/ibss.c | 9 ++++----- + net/mac80211/ieee80211_i.h | 6 +++--- + net/mac80211/scan.c | 34 ++++++++++++++++++++++++---------- + 3 files changed, 31 insertions(+), 18 deletions(-) + +diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c +index c21e33d..d9df6b8 100644 +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -678,8 +678,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) + sdata_info(sdata, + "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); + +- ieee80211_request_internal_scan(sdata, +- ifibss->ssid, ifibss->ssid_len, NULL); ++ ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, ++ NULL); + } + + static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) +@@ -777,9 +777,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) + IEEE80211_SCAN_INTERVAL)) { + sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); + +- ieee80211_request_internal_scan(sdata, +- ifibss->ssid, ifibss->ssid_len, +- ifibss->fixed_channel ? ifibss->channel : NULL); ++ ieee80211_request_ibss_scan(sdata, ifibss->ssid, ++ ifibss->ssid_len, chan); + } else { + int interval = IEEE80211_SCAN_INTERVAL; + +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 156e583..bc48d4d 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1247,9 +1247,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + + /* scan/BSS handling */ + void ieee80211_scan_work(struct work_struct *work); +-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, +- const u8 *ssid, u8 ssid_len, +- struct ieee80211_channel *chan); ++int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, ++ const u8 *ssid, u8 ssid_len, ++ struct ieee80211_channel *chan); + int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, + struct cfg80211_scan_request *req); + void ieee80211_scan_cancel(struct ieee80211_local *local); +diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c +index 43e60b5..fab706f 100644 +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -819,9 +819,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, + return res; + } + +-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, +- const u8 *ssid, u8 ssid_len, +- struct ieee80211_channel *chan) ++int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, ++ const u8 *ssid, u8 ssid_len, ++ struct ieee80211_channel *chan) + { + struct ieee80211_local *local = sdata->local; + int ret = -EBUSY; +@@ -835,22 +835,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, + + /* fill internal scan request */ + if (!chan) { +- int i, nchan = 0; ++ int i, max_n; ++ int n_ch = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!local->hw.wiphy->bands[band]) + continue; +- for (i = 0; +- i < local->hw.wiphy->bands[band]->n_channels; +- i++) { +- local->int_scan_req->channels[nchan] = ++ ++ max_n = local->hw.wiphy->bands[band]->n_channels; ++ for (i = 0; i < max_n; i++) { ++ struct ieee80211_channel *tmp_ch = + &local->hw.wiphy->bands[band]->channels[i]; +- nchan++; ++ ++ if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_DISABLED)) ++ continue; ++ ++ local->int_scan_req->channels[n_ch] = tmp_ch; ++ n_ch++; + } + } + +- local->int_scan_req->n_channels = nchan; ++ if (WARN_ON_ONCE(n_ch == 0)) ++ goto unlock; ++ ++ local->int_scan_req->n_channels = n_ch; + } else { ++ if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_DISABLED))) ++ goto unlock; ++ + local->int_scan_req->channels[0] = chan; + local->int_scan_req->n_channels = 1; + } +-- +1.7.1 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-wireless" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch b/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch new file mode 100644 index 000000000..abacee637 --- /dev/null +++ b/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch @@ -0,0 +1,47 @@ +Since: + +commit 816c04fe7ef01dd9649f5ccfe796474db8708be5 +Author: Christian Lamparter +Date: Sat Apr 30 15:24:30 2011 +0200 + + mac80211: consolidate MIC failure report handling + +is possible to that we dereference rx->key == NULL when driver set +RX_FLAG_MMIC_STRIPPED and not RX_FLAG_IV_STRIPPED and we are in +promiscuous mode. This happen with rt73usb and rt61pci at least. + +Before the commit we always check rx->key against NULL, so I assume +fix should be done in mac80211 (also mic_fail path has similar check). + +References: +https://bugzilla.redhat.com/show_bug.cgi?id=769766 +http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/2012-January/004395.html + +Cc: stable@vger.kernel.org # 3.0+ +Reported-by: Stuart D Gathman +Reported-by: Kai Wohlfahrt +Signed-off-by: Stanislaw Gruszka +--- + net/mac80211/wpa.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c +index 93aab07..422b798 100644 +--- a/net/mac80211/wpa.c ++++ b/net/mac80211/wpa.c +@@ -106,7 +106,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + +- if (!(status->flag & RX_FLAG_IV_STRIPPED)) ++ if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) + goto update_iv; + + return RX_CONTINUE; +-- +1.7.1 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-wireless" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/neuter_intel_microcode_load.patch b/neuter_intel_microcode_load.patch deleted file mode 100644 index 2766e439d..000000000 --- a/neuter_intel_microcode_load.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c -index ebd193e..c57024a 100644 ---- a/arch/x86/kernel/microcode_intel.c -+++ b/arch/x86/kernel/microcode_intel.c -@@ -453,9 +453,18 @@ static void microcode_fini_cpu(int cpu) - uci->mc = NULL; - } - -+/* we don't ship the broken out files... -+ * instead, we'll just fail here, and load it with microcode_ctl -+ */ -+static enum ucode_state noop_request_microcode_fw(int cpu, -+ struct device *device) -+{ -+ return UCODE_NFOUND; -+} -+ - static struct microcode_ops microcode_intel_ops = { - .request_microcode_user = request_microcode_user, -- .request_microcode_fw = request_microcode_fw, -+ .request_microcode_fw = noop_request_microcode_fw, - .collect_cpu_info = collect_cpu_info, - .apply_microcode = apply_microcode, - .microcode_fini_cpu = microcode_fini_cpu, diff --git a/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch b/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch new file mode 100644 index 000000000..38c96caed --- /dev/null +++ b/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch @@ -0,0 +1,47 @@ +>From e540f21852043a4d8e8cf5e505607909d0ab0f51 Mon Sep 17 00:00:00 2001 +From: Tim Gardner +Date: Thu, 29 Mar 2012 06:21:01 -0600 +Subject: [PATCH] UBUNTU: SAUCE: disable_nx should not be in __cpuinitdata + section for X86_32 + +I noticed a section mismatch warning while building 3.2.0-20.33 for X86_32. + + AR arch/x86/lib/lib.a + LD vmlinux.o + MODPOST vmlinux.o +WARNING: vmlinux.o(.text+0x187833): Section mismatch in reference from the function load_elf_binary() to the variable .cpuinit.data:disable_nx +The function load_elf_binary() references +the variable __cpuinitdata disable_nx. +This is often because load_elf_binary lacks a __cpuinitdata +annotation or the annotation of disable_nx is wrong. + +load_elf_binary() is definitely called after initialization. + +This code was added by 'UBUNTU: ubuntu: nx-emu - i386: NX emulation', so +this is not an upstream problem. + +Reported-by: Tetsuo Handa +Signed-off-by: Tim Gardner +--- + arch/x86/mm/setup_nx.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c +index 90c9eff3..89fd946 100644 +--- a/arch/x86/mm/setup_nx.c ++++ b/arch/x86/mm/setup_nx.c +@@ -6,7 +6,11 @@ + #include + #include + ++#ifdef CONFIG_X86_32 ++int disable_nx; /* referenced by load_elf_binary() */ ++#else + int disable_nx __cpuinitdata; ++#endif + + /* + * noexec = on|off +-- +1.7.9.1 + diff --git a/pci-crs-blacklist.patch b/pci-crs-blacklist.patch new file mode 100644 index 000000000..76dc22caa --- /dev/null +++ b/pci-crs-blacklist.patch @@ -0,0 +1,74 @@ +diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c +index 404f21a..2704a9c 100644 +--- a/arch/x86/pci/acpi.c ++++ b/arch/x86/pci/acpi.c +@@ -24,6 +24,12 @@ static int __init set_use_crs(const struct dmi_system_id *id) + return 0; + } + ++static int __init set_nouse_crs(const struct dmi_system_id *id) ++{ ++ pci_use_crs = false; ++ return 0; ++} ++ + static const struct dmi_system_id pci_use_crs_table[] __initconst = { + /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ + { +@@ -54,6 +60,18 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + }, + }, ++ ++ /* Now for the blacklist.. */ ++ ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=770308 */ ++ { ++ .callback = set_nouse_crs, ++ .ident = "Dell Studio 1536", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_BOARD_NAME, "0M273C"), ++ }, ++ }, + {} + }; + +--- linux-3.1.noarch/arch/x86/pci/acpi.c~ 2011-12-30 14:42:43.495717907 -0500 ++++ linux-3.1.noarch/arch/x86/pci/acpi.c 2011-12-30 14:45:09.296198024 -0500 +@@ -72,6 +72,16 @@ static const struct dmi_system_id pci_us + DMI_MATCH(DMI_BOARD_NAME, "0M273C"), + }, + }, ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */ ++ { ++ .callback = set_nouse_crs, ++ .ident = "Thinkpad SL510", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "2847DFG"), ++ DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), ++ }, ++ }, + {} + }; + +--- linux-3.1.noarch/arch/x86/pci/acpi.c~ 2012-01-04 11:19:36.783664477 -0500 ++++ linux-3.1.noarch/arch/x86/pci/acpi.c 2012-01-04 11:23:42.403666272 -0500 +@@ -75,6 +75,16 @@ static const struct dmi_system_id pci_us + /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */ + { + .callback = set_nouse_crs, ++ .ident = "Dell Studio 1557", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"), ++ DMI_MATCH(DMI_BIOS_VERSION, "A09"), ++ }, ++ }, ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */ ++ { ++ .callback = set_nouse_crs, + .ident = "Thinkpad SL510", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), diff --git a/quite-apm.patch b/quite-apm.patch new file mode 100644 index 000000000..c38511c41 --- /dev/null +++ b/quite-apm.patch @@ -0,0 +1,13 @@ +diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c +index a46bd38..416dd12 100644 +--- a/arch/x86/kernel/apm_32.c ++++ b/arch/x86/kernel/apm_32.c +@@ -903,7 +903,7 @@ static void apm_cpu_idle(void) + unsigned int jiffies_since_last_check = jiffies - last_jiffies; + unsigned int bucket; + +- WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012"); ++ printk_once(KERN_INFO "deprecated apm_cpu_idle will be deleted in 2012"); + recalc: + if (jiffies_since_last_check > IDLE_CALC_LIMIT) { + use_apm_idle = 0; diff --git a/runtime_pm_fixups.patch b/runtime_pm_fixups.patch deleted file mode 100644 index 1be6149d6..000000000 --- a/runtime_pm_fixups.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 141d0d01ab292d4ea3a6d5e96b4048e10e68c1d3 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 24 Jan 2011 13:01:57 -0500 -Subject: [PATCH] runtime_pm_fixups - ---- - drivers/acpi/bus.c | 3 ++- - drivers/acpi/pci_bind.c | 6 ++++++ - drivers/acpi/power.c | 5 ++++- - drivers/acpi/sleep.c | 2 +- - drivers/acpi/wakeup.c | 2 +- - drivers/pci/pci-acpi.c | 2 +- - include/acpi/acpi_bus.h | 2 +- - 7 files changed, 16 insertions(+), 6 deletions(-) - -diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c -index 7ced61f..e4e0114 100644 ---- a/drivers/acpi/bus.c -+++ b/drivers/acpi/bus.c -@@ -256,7 +256,8 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) - * a lower-powered state. - */ - if (state < device->power.state) { -- if (device->power.flags.power_resources) { -+ if (device->power.flags.power_resources && -+ !device->wakeup.run_wake_count) { - result = acpi_power_transition(device, state); - if (result) - goto end; -diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c -index 2ef0409..4b0bb68 100644 ---- a/drivers/acpi/pci_bind.c -+++ b/drivers/acpi/pci_bind.c -@@ -32,6 +32,8 @@ - #include - #include - -+#include "internal.h" -+ - #define _COMPONENT ACPI_PCI_COMPONENT - ACPI_MODULE_NAME("pci_bind"); - -@@ -65,6 +67,7 @@ static int acpi_pci_bind(struct acpi_device *device) - acpi_handle handle; - struct pci_bus *bus; - struct pci_dev *dev; -+ int state; - - dev = acpi_get_pci_dev(device->handle); - if (!dev) -@@ -87,6 +90,9 @@ static int acpi_pci_bind(struct acpi_device *device) - device->ops.unbind = acpi_pci_unbind; - } - -+ acpi_power_get_inferred_state(device, &state); -+ acpi_power_transition(device, state); -+ - /* - * Evaluate and parse _PRT, if exists. This code allows parsing of - * _PRT objects within the scope of non-bridge devices. Note that -diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c -index 9ac2a9f..cd6a8df 100644 ---- a/drivers/acpi/power.c -+++ b/drivers/acpi/power.c -@@ -412,7 +412,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) - * State Wake) for the device, if present - * 2. Shutdown down the power resources - */ --int acpi_disable_wakeup_device_power(struct acpi_device *dev) -+int acpi_disable_wakeup_device_power(struct acpi_device *dev, int sleep_state) - { - int i, err = 0; - -@@ -435,6 +435,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) - if (err) - goto out; - -+ if (sleep_state == ACPI_STATE_S0) -+ goto out; -+ - /* Close power resource */ - for (i = 0; i < dev->wakeup.resources.count; i++) { - int ret = acpi_power_off(dev->wakeup.resources.handles[i]); -diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c -index d6a8cd1..5d68dc0 100644 ---- a/drivers/acpi/sleep.c -+++ b/drivers/acpi/sleep.c -@@ -697,7 +697,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) - - error = enable ? - acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : -- acpi_disable_wakeup_device_power(adev); -+ acpi_disable_wakeup_device_power(adev, acpi_target_sleep_state); - if (!error) - dev_info(dev, "wake-up capability %s by ACPI\n", - enable ? "enabled" : "disabled"); -diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c -index ed65014..a0cabc3 100644 ---- a/drivers/acpi/wakeup.c -+++ b/drivers/acpi/wakeup.c -@@ -73,7 +73,7 @@ void acpi_disable_wakeup_devices(u8 sleep_state) - ACPI_GPE_DISABLE); - - if (device_may_wakeup(&dev->dev)) -- acpi_disable_wakeup_device_power(dev); -+ acpi_disable_wakeup_device_power(dev, sleep_state); - } - } - -diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c -index 6fe0772..819fa7a 100644 ---- a/drivers/pci/pci-acpi.c -+++ b/drivers/pci/pci-acpi.c -@@ -302,7 +302,7 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) - if (!--dev->wakeup.run_wake_count) { - acpi_disable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); -- acpi_disable_wakeup_device_power(dev); -+ acpi_disable_wakeup_device_power(dev, ACPI_STATE_S0); - } - } else { - error = -EALREADY; -diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h -index 78ca429..92d6e86 100644 ---- a/include/acpi/acpi_bus.h -+++ b/include/acpi/acpi_bus.h -@@ -379,7 +379,7 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); - #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) - - int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); --int acpi_disable_wakeup_device_power(struct acpi_device *dev); -+int acpi_disable_wakeup_device_power(struct acpi_device *dev, int state); - - #ifdef CONFIG_PM_OPS - int acpi_pm_device_sleep_state(struct device *, int *); --- -1.7.3.5 - diff --git a/scripts/grab-logs.sh b/scripts/grab-logs.sh index 8a445ec99..5df573571 100755 --- a/scripts/grab-logs.sh +++ b/scripts/grab-logs.sh @@ -1,6 +1,6 @@ #!/bin/sh -VER=$(make verrel) +VER=$(fedpkg verrel) ver=$(echo $VER | sed -e 's/-/ /g' | awk '{print $2}') rev=$(echo $VER | sed -e 's/-/ /g' | awk '{print $3}') diff --git a/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch b/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch new file mode 100644 index 000000000..48db13328 --- /dev/null +++ b/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch @@ -0,0 +1,22 @@ +--- a/drivers/scsi/sd.c ++++ a/drivers/scsi/sd.c +@@ -2362,13 +2362,18 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp) + static int sd_revalidate_disk(struct gendisk *disk) + { + struct scsi_disk *sdkp = scsi_disk(disk); +- struct scsi_device *sdp = sdkp->device; ++ struct scsi_device *sdp; + unsigned char *buffer; + unsigned flush = 0; + + SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, + "sd_revalidate_disk\n")); + ++ if (WARN_ONCE((!sdkp), "Invalid scsi_disk from %p\n", disk)) ++ goto out; ++ ++ sdp = sdkp->device; ++ + /* + * If the device is offline, don't try and read capacity or any + * of the other niceties. diff --git a/shlib_base_randomize.patch b/shlib_base_randomize.patch new file mode 100644 index 000000000..80e4d644b --- /dev/null +++ b/shlib_base_randomize.patch @@ -0,0 +1,69 @@ +diff -uNrp kernel-3.2.fc16.orig/arch/x86/mm/mmap.c kernel-3.2.fc16.new/arch/x86/mm/mmap.c +--- kernel-3.2.fc16.orig/arch/x86/mm/mmap.c 2012-03-19 16:47:03.495169091 -0400 ++++ kernel-3.2.fc16.new/arch/x86/mm/mmap.c 2012-03-19 16:50:03.574168052 -0400 +@@ -106,6 +106,10 @@ static unsigned long mmap_legacy_base(vo + return TASK_UNMAPPED_BASE + mmap_rnd(); + } + ++#ifdef CONFIG_X86_32 ++ #define SHLIB_BASE 0x00111000 ++#endif ++ + /* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: +@@ -126,8 +126,10 @@ void arch_pick_mmap_layout(struct mm_str + #ifdef CONFIG_X86_32 + if (!(current->personality & READ_IMPLIES_EXEC) + && !(__supported_pte_mask & _PAGE_NX) +- && mmap_is_ia32()) ++ && mmap_is_ia32()) { ++ mm->shlib_base = SHLIB_BASE + mmap_rnd(); + mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; ++ } + #endif + mm->unmap_area = arch_unmap_area_topdown; + } +diff -uNrp kernel-3.2.fc16.orig/include/linux/mm_types.h kernel-3.2.fc16.new/include/linux/mm_types.h +--- kernel-3.2.fc16.orig/include/linux/mm_types.h 2012-03-19 16:46:47.382169153 -0400 ++++ kernel-3.2.fc16.new/include/linux/mm_types.h 2012-03-19 16:50:40.738168219 -0400 +@@ -300,6 +300,7 @@ struct mm_struct { + void (*unmap_area) (struct mm_struct *mm, unsigned long addr); + #endif + unsigned long mmap_base; /* base of mmap area */ ++ unsigned long shlib_base; /* base of lib map area (ASCII armour)*/ + unsigned long task_size; /* size of task vm space */ + unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ + unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ +diff -uNrp kernel-3.2.fc16.orig/mm/mmap.c kernel-3.2.fc16.new/mm/mmap.c +--- kernel-3.2.fc16.orig/mm/mmap.c 2012-03-19 16:46:15.791169274 -0400 ++++ kernel-3.2.fc16.new/mm/mmap.c 2012-03-19 16:51:37.351166875 -0400 +@@ -1594,8 +1594,6 @@ static bool should_randomize(void) + !(current->personality & ADDR_NO_RANDOMIZE); + } + +-#define SHLIB_BASE 0x00110000 +- + unsigned long + arch_get_unmapped_exec_area(struct file *filp, unsigned long addr0, + unsigned long len0, unsigned long pgoff, unsigned long flags) +@@ -1612,8 +1610,8 @@ arch_get_unmapped_exec_area(struct file + return addr; + + if (!addr) +- addr = !should_randomize() ? SHLIB_BASE : +- randomize_range(SHLIB_BASE, 0x01000000, len); ++ addr = !should_randomize() ? mm->shlib_base : ++ randomize_range(mm->shlib_base, 0x01000000, len); + + if (addr) { + addr = PAGE_ALIGN(addr); +@@ -1623,7 +1621,7 @@ arch_get_unmapped_exec_area(struct file + return addr; + } + +- addr = SHLIB_BASE; ++ addr = mm->shlib_base; + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) diff --git a/silence-empty-ipi-mask-warning.patch b/silence-empty-ipi-mask-warning.patch new file mode 100644 index 000000000..65a637c06 --- /dev/null +++ b/silence-empty-ipi-mask-warning.patch @@ -0,0 +1,11 @@ +--- linux-3.6.noarch/arch/x86/kernel/apic/ipi.c~ 2013-01-23 10:48:14.716069615 -0500 ++++ linux-3.6.noarch/arch/x86/kernel/apic/ipi.c 2013-01-23 10:48:26.217046545 -0500 +@@ -106,7 +106,7 @@ void default_send_IPI_mask_logical(const + unsigned long mask = cpumask_bits(cpumask)[0]; + unsigned long flags; + +- if (WARN_ONCE(!mask, "empty IPI mask")) ++ if (!mask) + return; + + local_irq_save(flags); diff --git a/smp_irq_move_cleanup_interrupt.patch b/smp_irq_move_cleanup_interrupt.patch new file mode 100644 index 000000000..c9b385a94 --- /dev/null +++ b/smp_irq_move_cleanup_interrupt.patch @@ -0,0 +1,50 @@ +commit 94777fc51b3ad85ff9f705ddf7cdd0eb3bbad5a6 +Author: Dimitri Sivanich +Date: Tue Oct 16 07:50:21 2012 -0500 + + x86/irq/ioapic: Check for valid irq_cfg pointer in smp_irq_move_cleanup_interrupt + + Posting this patch to fix an issue concerning sparse irq's that + I raised a while back. There was discussion about adding + refcounting to sparse irqs (to fix other potential race + conditions), but that does not appear to have been addressed + yet. This covers the only issue of this type that I've + encountered in this area. + + A NULL pointer dereference can occur in + smp_irq_move_cleanup_interrupt() if we haven't yet setup the + irq_cfg pointer in the irq_desc.irq_data.chip_data. + + In create_irq_nr() there is a window where we have set + vector_irq in __assign_irq_vector(), but not yet called + irq_set_chip_data() to set the irq_cfg pointer. + + Should an IRQ_MOVE_CLEANUP_VECTOR hit the cpu in question during + this time, smp_irq_move_cleanup_interrupt() will attempt to + process the aforementioned irq, but panic when accessing + irq_cfg. + + Only continue processing the irq if irq_cfg is non-NULL. + + Signed-off-by: Dimitri Sivanich + Cc: Suresh Siddha + Cc: Joerg Roedel + Cc: Yinghai Lu + Cc: Alexander Gordeev + Link: http://lkml.kernel.org/r/20121016125021.GA22935@sgi.com + Signed-off-by: Ingo Molnar + +diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c +index c265593..1817fa9 100644 +--- a/arch/x86/kernel/apic/io_apic.c ++++ b/arch/x86/kernel/apic/io_apic.c +@@ -2257,6 +2257,9 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void) + continue; + + cfg = irq_cfg(irq); ++ if (!cfg) ++ continue; ++ + raw_spin_lock(&desc->lock); + + /* diff --git a/sources b/sources index 9167d7bae..fdb1a3193 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -398e95866794def22b12dfbc15ce89c0 linux-3.0.tar.bz2 -ce0c7face215619004aeac9c85c36324 patch-3.0-git3.bz2 +1a1760420eac802c541a20ab51a093d1 linux-3.6.tar.xz +bd4bba74093405887d521309a74c19e9 patch-3.6.11.xz diff --git a/taint-vbox.patch b/taint-vbox.patch new file mode 100644 index 000000000..5cb3e47c9 --- /dev/null +++ b/taint-vbox.patch @@ -0,0 +1,15 @@ +diff --git a/kernel/module.c b/kernel/module.c +index 04379f92..d26c9a3 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2653,6 +2653,10 @@ static int check_module_license_and_versions(struct module *mod) + if (strcmp(mod->name, "ndiswrapper") == 0) + add_taint(TAINT_PROPRIETARY_MODULE); + ++ /* vbox is garbage. */ ++ if (strcmp(mod->name, "vboxdrv") == 0) ++ add_taint(TAINT_CRAP); ++ + /* driverloader was caught wrongly pretending to be under GPL */ + if (strcmp(mod->name, "driverloader") == 0) + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); diff --git a/thp-reduce-khugepaged-freezing-latency.patch b/thp-reduce-khugepaged-freezing-latency.patch new file mode 100644 index 000000000..b7b205177 --- /dev/null +++ b/thp-reduce-khugepaged-freezing-latency.patch @@ -0,0 +1,54 @@ +From: Andrea Arcangeli +Subject: thp: reduce khugepaged freezing latency + +Use wait_event_freezable_timeout() instead of +schedule_timeout_interruptible() to avoid missing freezer wakeups. A +try_to_freeze() would have been needed in the +khugepaged_alloc_hugepage tight loop too in case of the allocation +failing repeatedly, and wait_event_freezable_timeout will provide it +too. + +khugepaged would still freeze just fine by trying again the next +minute but it's better if it freezes immediately. + +Reported-by: Jiri Slaby +Signed-off-by: Andrea Arcangeli + +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index 4298aba..fd925d0 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -2259,12 +2259,9 @@ static void khugepaged_do_scan(struct page **hpage) + + static void khugepaged_alloc_sleep(void) + { +- DEFINE_WAIT(wait); +- add_wait_queue(&khugepaged_wait, &wait); +- schedule_timeout_interruptible( +- msecs_to_jiffies( +- khugepaged_alloc_sleep_millisecs)); +- remove_wait_queue(&khugepaged_wait, &wait); ++ wait_event_freezable_timeout(khugepaged_wait, false, ++ msecs_to_jiffies( ++ khugepaged_alloc_sleep_millisecs)); + } + + #ifndef CONFIG_NUMA +@@ -2313,14 +2310,11 @@ static void khugepaged_loop(void) + if (unlikely(kthread_should_stop())) + break; + if (khugepaged_has_work()) { +- DEFINE_WAIT(wait); + if (!khugepaged_scan_sleep_millisecs) + continue; +- add_wait_queue(&khugepaged_wait, &wait); +- schedule_timeout_interruptible( ++ wait_event_freezable_timeout(khugepaged_wait, false, + msecs_to_jiffies( + khugepaged_scan_sleep_millisecs)); +- remove_wait_queue(&khugepaged_wait, &wait); + } else if (khugepaged_enabled()) + wait_event_freezable(khugepaged_wait, + khugepaged_wait_event()); + + diff --git a/uprobes-task_work_add-generic-process-context-callbacks.patch b/uprobes-task_work_add-generic-process-context-callbacks.patch new file mode 100644 index 000000000..6f56b4261 --- /dev/null +++ b/uprobes-task_work_add-generic-process-context-callbacks.patch @@ -0,0 +1,249 @@ +FYI. This patch is upstream since linux-3.5. Backported in order to +bring SystemTap functionality back after the switch to linux-3.4 that +doesn't have utrace. :) + +The split-out series is available in the git repository at: + + git://fedorapeople.org/home/fedora/aarapov/public_git/kernel-uprobes.git + +Oleg Nesterov (1): + task_work_add: generic process-context callbacks + +Signed-off-by: Anton Arapov +--- + include/linux/sched.h | 2 ++ + include/linux/task_work.h | 33 ++++++++++++++++++ + include/linux/tracehook.h | 11 ++++++ + kernel/Makefile | 2 +- + kernel/exit.c | 5 ++- + kernel/fork.c | 1 + + kernel/task_work.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 136 insertions(+), 2 deletions(-) + create mode 100644 include/linux/task_work.h + create mode 100644 kernel/task_work.c + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 6869c60..e011a11 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1445,6 +1445,8 @@ struct task_struct { + int (*notifier)(void *priv); + void *notifier_data; + sigset_t *notifier_mask; ++ struct hlist_head task_works; ++ + struct audit_context *audit_context; + #ifdef CONFIG_AUDITSYSCALL + uid_t loginuid; +diff --git a/include/linux/task_work.h b/include/linux/task_work.h +new file mode 100644 +index 0000000..294d5d5 +--- /dev/null ++++ b/include/linux/task_work.h +@@ -0,0 +1,33 @@ ++#ifndef _LINUX_TASK_WORK_H ++#define _LINUX_TASK_WORK_H ++ ++#include ++#include ++ ++struct task_work; ++typedef void (*task_work_func_t)(struct task_work *); ++ ++struct task_work { ++ struct hlist_node hlist; ++ task_work_func_t func; ++ void *data; ++}; ++ ++static inline void ++init_task_work(struct task_work *twork, task_work_func_t func, void *data) ++{ ++ twork->func = func; ++ twork->data = data; ++} ++ ++int task_work_add(struct task_struct *task, struct task_work *twork, bool); ++struct task_work *task_work_cancel(struct task_struct *, task_work_func_t); ++void task_work_run(void); ++ ++static inline void exit_task_work(struct task_struct *task) ++{ ++ if (unlikely(!hlist_empty(&task->task_works))) ++ task_work_run(); ++} ++ ++#endif /* _LINUX_TASK_WORK_H */ +diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h +index 51bd91d..48c597d 100644 +--- a/include/linux/tracehook.h ++++ b/include/linux/tracehook.h +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + struct linux_binprm; + + /* +@@ -165,8 +166,10 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, + */ + static inline void set_notify_resume(struct task_struct *task) + { ++#ifdef TIF_NOTIFY_RESUME + if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME)) + kick_process(task); ++#endif + } + + /** +@@ -184,6 +187,14 @@ static inline void set_notify_resume(struct task_struct *task) + */ + static inline void tracehook_notify_resume(struct pt_regs *regs) + { ++ /* ++ * The caller just cleared TIF_NOTIFY_RESUME. This barrier ++ * pairs with task_work_add()->set_notify_resume() after ++ * hlist_add_head(task->task_works); ++ */ ++ smp_mb__after_clear_bit(); ++ if (unlikely(!hlist_empty(¤t->task_works))) ++ task_work_run(); + } + #endif /* TIF_NOTIFY_RESUME */ + +diff --git a/kernel/Makefile b/kernel/Makefile +index cb41b95..2479528 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -5,7 +5,7 @@ + obj-y = fork.o exec_domain.o panic.o printk.o \ + cpu.o exit.o itimer.o time.o softirq.o resource.o \ + sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ +- signal.o sys.o kmod.o workqueue.o pid.o \ ++ signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ + rcupdate.o extable.o params.o posix-timers.o \ + kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ + hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ +diff --git a/kernel/exit.c b/kernel/exit.c +index d8bd3b42..b82c38e 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -946,11 +946,14 @@ void do_exit(long code) + exit_signals(tsk); /* sets PF_EXITING */ + /* + * tsk->flags are checked in the futex code to protect against +- * an exiting task cleaning up the robust pi futexes. ++ * an exiting task cleaning up the robust pi futexes, and in ++ * task_work_add() to avoid the race with exit_task_work(). + */ + smp_mb(); + raw_spin_unlock_wait(&tsk->pi_lock); + ++ exit_task_work(tsk); ++ + exit_irq_thread(); + + if (unlikely(in_atomic())) +diff --git a/kernel/fork.c b/kernel/fork.c +index 5b87e9f..76a961d 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1391,6 +1391,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, + */ + p->group_leader = p; + INIT_LIST_HEAD(&p->thread_group); ++ INIT_HLIST_HEAD(&p->task_works); + + /* Now that the task is set up, run cgroup callbacks if + * necessary. We need to run them before the task is visible +diff --git a/kernel/task_work.c b/kernel/task_work.c +new file mode 100644 +index 0000000..82d1c79 +--- /dev/null ++++ b/kernel/task_work.c +@@ -0,0 +1,84 @@ ++#include ++#include ++#include ++ ++int ++task_work_add(struct task_struct *task, struct task_work *twork, bool notify) ++{ ++ unsigned long flags; ++ int err = -ESRCH; ++ ++#ifndef TIF_NOTIFY_RESUME ++ if (notify) ++ return -ENOTSUPP; ++#endif ++ /* ++ * We must not insert the new work if the task has already passed ++ * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait() ++ * and check PF_EXITING under pi_lock. ++ */ ++ raw_spin_lock_irqsave(&task->pi_lock, flags); ++ if (likely(!(task->flags & PF_EXITING))) { ++ hlist_add_head(&twork->hlist, &task->task_works); ++ err = 0; ++ } ++ raw_spin_unlock_irqrestore(&task->pi_lock, flags); ++ ++ /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */ ++ if (likely(!err) && notify) ++ set_notify_resume(task); ++ return err; ++} ++ ++struct task_work * ++task_work_cancel(struct task_struct *task, task_work_func_t func) ++{ ++ unsigned long flags; ++ struct task_work *twork; ++ struct hlist_node *pos; ++ ++ raw_spin_lock_irqsave(&task->pi_lock, flags); ++ hlist_for_each_entry(twork, pos, &task->task_works, hlist) { ++ if (twork->func == func) { ++ hlist_del(&twork->hlist); ++ goto found; ++ } ++ } ++ twork = NULL; ++ found: ++ raw_spin_unlock_irqrestore(&task->pi_lock, flags); ++ ++ return twork; ++} ++ ++void task_work_run(void) ++{ ++ struct task_struct *task = current; ++ struct hlist_head task_works; ++ struct hlist_node *pos; ++ ++ raw_spin_lock_irq(&task->pi_lock); ++ hlist_move_list(&task->task_works, &task_works); ++ raw_spin_unlock_irq(&task->pi_lock); ++ ++ if (unlikely(hlist_empty(&task_works))) ++ return; ++ /* ++ * We use hlist to save the space in task_struct, but we want fifo. ++ * Find the last entry, the list should be short, then process them ++ * in reverse order. ++ */ ++ for (pos = task_works.first; pos->next; pos = pos->next) ++ ; ++ ++ for (;;) { ++ struct hlist_node **pprev = pos->pprev; ++ struct task_work *twork = container_of(pos, struct task_work, ++ hlist); ++ twork->func(twork); ++ ++ if (pprev == &task_works.first) ++ break; ++ pos = container_of(pprev, struct hlist_node, next); ++ } ++} diff --git a/utrace.patch b/utrace.patch deleted file mode 100644 index 55d0b3c1b..000000000 --- a/utrace.patch +++ /dev/null @@ -1,6166 +0,0 @@ -From davej Thu Jun 30 20:27:03 2011 -Return-Path: oleg@redhat.com -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:03 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:00 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 10DAED812A; - Thu, 30 Jun 2011 20:23:00 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id fiwBBweCuo8A; Thu, 30 Jun 2011 20:22:59 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E7CA2D810F; - Thu, 30 Jun 2011 20:22:59 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610MpCP015143; - Thu, 30 Jun 2011 20:22:52 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:20:59 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:20:57 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 01/19] utrace core -Message-ID: <20110701002057.GA25776@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 148213 -Lines: 4119 - -From: Roland McGrath - -This adds the utrace facility, a new modular interface in the kernel for -implementing user thread tracing and debugging. This fits on top of the -tracehook_* layer, so the new code is well-isolated. - -The new interface is in and the DocBook utrace book -describes it. It allows for multiple separate tracing engines to work in -parallel without interfering with each other. Higher-level tracing -facilities can be implemented as loadable kernel modules using this layer. - -The new facility is made optional under CONFIG_UTRACE. -When this is not enabled, no new code is added. -It can only be enabled on machines that have all the -prerequisites and select CONFIG_HAVE_ARCH_TRACEHOOK. - -In this initial version, utrace and ptrace do not play together at all, -the next patches try to fix this. - -This is is same/old utrace-core patch except: - - - use group_stop/GROUP_STOP_DEQUEUED instead of removed - signal->flags/SIGNAL_STOP_DEQUEUED in utrace_get_signal() - - - rediff the changes in tracehook.h against the current code - without PT_PTRACED tweaks which were needed for ptrace-utrace - -Signed-off-by: Roland McGrath -Signed-off-by: Oleg Nesterov ---- - Documentation/DocBook/Makefile | 2 +- - Documentation/DocBook/utrace.tmpl | 589 +++++++++ - fs/proc/array.c | 3 + - include/linux/sched.h | 5 + - include/linux/tracehook.h | 85 ++- - include/linux/utrace.h | 692 +++++++++++ - init/Kconfig | 9 + - kernel/Makefile | 1 + - kernel/fork.c | 3 + - kernel/utrace.c | 2440 +++++++++++++++++++++++++++++++++++++ - 10 files changed, 3827 insertions(+), 2 deletions(-) - create mode 100644 Documentation/DocBook/utrace.tmpl - create mode 100644 include/linux/utrace.h - create mode 100644 kernel/utrace.c - -diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index 3cebfa0..86c288b 100644 ---- a/Documentation/DocBook/Makefile -+++ b/Documentation/DocBook/Makefile -@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ - genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - 80211.xml debugobjects.xml sh.xml regulator.xml \ - alsa-driver-api.xml writing-an-alsa-driver.xml \ -- tracepoint.xml media.xml drm.xml -+ tracepoint.xml utrace.xml media.xml drm.xml - - ### - # The build process is as follows (targets): -diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl -new file mode 100644 -index 0000000..0c40add ---- /dev/null -+++ b/Documentation/DocBook/utrace.tmpl -@@ -0,0 +1,589 @@ -+ -+ -+ -+ -+ -+ The utrace User Debugging Infrastructure -+ -+ -+ -+ -+ utrace concepts -+ -+ Introduction -+ -+ -+ utrace is infrastructure code for tracing -+ and controlling user threads. This is the foundation for writing -+ tracing engines, which can be loadable kernel modules. -+ -+ -+ -+ The basic actors in utrace are the thread -+ and the tracing engine. A tracing engine is some body of code that -+ calls into the <linux/utrace.h> -+ interfaces, represented by a struct -+ utrace_engine_ops. (Usually it's a kernel module, -+ though the legacy ptrace support is a tracing -+ engine that is not in a kernel module.) The interface operates on -+ individual threads (struct task_struct). -+ If an engine wants to treat several threads as a group, that is up -+ to its higher-level code. -+ -+ -+ -+ Tracing begins by attaching an engine to a thread, using -+ utrace_attach_task or -+ utrace_attach_pid. If successful, it returns a -+ pointer that is the handle used in all other calls. -+ -+ -+ -+ -+ Events and Callbacks -+ -+ -+ An attached engine does nothing by default. An engine makes something -+ happen by requesting callbacks via utrace_set_events -+ and poking the thread with utrace_control. -+ The synchronization issues related to these two calls -+ are discussed further below in . -+ -+ -+ -+ Events are specified using the macro -+ UTRACE_EVENT(type). -+ Each event type is associated with a callback in struct -+ utrace_engine_ops. A tracing engine can leave unused -+ callbacks NULL. The only callbacks required -+ are those used by the event flags it sets. -+ -+ -+ -+ Many engines can be attached to each thread. When a thread has an -+ event, each engine gets a callback if it has set the event flag for -+ that event type. For most events, engines are called in the order they -+ attached. Engines that attach after the event has occurred do not get -+ callbacks for that event. This includes any new engines just attached -+ by an existing engine's callback function. Once the sequence of -+ callbacks for that one event has completed, such new engines are then -+ eligible in the next sequence that starts when there is another event. -+ -+ -+ -+ Event reporting callbacks have details particular to the event type, -+ but are all called in similar environments and have the same -+ constraints. Callbacks are made from safe points, where no locks -+ are held, no special resources are pinned (usually), and the -+ user-mode state of the thread is accessible. So, callback code has -+ a pretty free hand. But to be a good citizen, callback code should -+ never block for long periods. It is fine to block in -+ kmalloc and the like, but never wait for i/o or -+ for user mode to do something. If you need the thread to wait, use -+ UTRACE_STOP and return from the callback -+ quickly. When your i/o finishes or whatever, you can use -+ utrace_control to resume the thread. -+ -+ -+ -+ The UTRACE_EVENT(SYSCALL_ENTRY) event is a special -+ case. While other events happen in the kernel when it will return to -+ user mode soon, this event happens when entering the kernel before it -+ will proceed with the work requested from user mode. Because of this -+ difference, the report_syscall_entry callback is -+ special in two ways. For this event, engines are called in reverse of -+ the normal order (this includes the report_quiesce -+ call that precedes a report_syscall_entry call). -+ This preserves the semantics that the last engine to attach is called -+ "closest to user mode"--the engine that is first to see a thread's user -+ state when it enters the kernel is also the last to see that state when -+ the thread returns to user mode. For the same reason, if these -+ callbacks use UTRACE_STOP (see the next section), -+ the thread stops immediately after callbacks rather than only when it's -+ ready to return to user mode; when allowed to resume, it will actually -+ attempt the system call indicated by the register values at that time. -+ -+ -+ -+ -+ Stopping Safely -+ -+ Writing well-behaved callbacks -+ -+ -+ Well-behaved callbacks are important to maintain two essential -+ properties of the interface. The first of these is that unrelated -+ tracing engines should not interfere with each other. If your engine's -+ event callback does not return quickly, then another engine won't get -+ the event notification in a timely manner. The second important -+ property is that tracing should be as noninvasive as possible to the -+ normal operation of the system overall and of the traced thread in -+ particular. That is, attached tracing engines should not perturb a -+ thread's behavior, except to the extent that changing its user-visible -+ state is explicitly what you want to do. (Obviously some perturbation -+ is unavoidable, primarily timing changes, ranging from small delays due -+ to the overhead of tracing, to arbitrary pauses in user code execution -+ when a user stops a thread with a debugger for examination.) Even when -+ you explicitly want the perturbation of making the traced thread block, -+ just blocking directly in your callback has more unwanted effects. For -+ example, the CLONE event callbacks are called when -+ the new child thread has been created but not yet started running; the -+ child can never be scheduled until the CLONE -+ tracing callbacks return. (This allows engines tracing the parent to -+ attach to the child.) If a CLONE event callback -+ blocks the parent thread, it also prevents the child thread from -+ running (even to process a SIGKILL). If what you -+ want is to make both the parent and child block, then use -+ utrace_attach_task on the child and then use -+ UTRACE_STOP on both threads. A more crucial -+ problem with blocking in callbacks is that it can prevent -+ SIGKILL from working. A thread that is blocking -+ due to UTRACE_STOP will still wake up and die -+ immediately when sent a SIGKILL, as all threads -+ should. Relying on the utrace -+ infrastructure rather than on private synchronization calls in event -+ callbacks is an important way to help keep tracing robustly -+ noninvasive. -+ -+ -+ -+ -+ Using <constant>UTRACE_STOP</constant> -+ -+ -+ To control another thread and access its state, it must be stopped -+ with UTRACE_STOP. This means that it is -+ stopped and won't start running again while we access it. When a -+ thread is not already stopped, utrace_control -+ returns -EINPROGRESS and an engine must wait -+ for an event callback when the thread is ready to stop. The thread -+ may be running on another CPU or may be blocked. When it is ready -+ to be examined, it will make callbacks to engines that set the -+ UTRACE_EVENT(QUIESCE) event bit. To wake up an -+ interruptible wait, use UTRACE_INTERRUPT. -+ -+ -+ -+ As long as some engine has used UTRACE_STOP and -+ not called utrace_control to resume the thread, -+ then the thread will remain stopped. SIGKILL -+ will wake it up, but it will not run user code. When the stop is -+ cleared with utrace_control or a callback -+ return value, the thread starts running again. -+ (See also .) -+ -+ -+ -+ -+ -+ -+ Tear-down Races -+ -+ Primacy of <constant>SIGKILL</constant> -+ -+ Ordinarily synchronization issues for tracing engines are kept fairly -+ straightforward by using UTRACE_STOP. You ask a -+ thread to stop, and then once it makes the -+ report_quiesce callback it cannot do anything else -+ that would result in another callback, until you let it with a -+ utrace_control call. This simple arrangement -+ avoids complex and error-prone code in each one of a tracing engine's -+ event callbacks to keep them serialized with the engine's other -+ operations done on that thread from another thread of control. -+ However, giving tracing engines complete power to keep a traced thread -+ stuck in place runs afoul of a more important kind of simplicity that -+ the kernel overall guarantees: nothing can prevent or delay -+ SIGKILL from making a thread die and release its -+ resources. To preserve this important property of -+ SIGKILL, it as a special case can break -+ UTRACE_STOP like nothing else normally can. This -+ includes both explicit SIGKILL signals and the -+ implicit SIGKILL sent to each other thread in the -+ same thread group by a thread doing an exec, or processing a fatal -+ signal, or making an exit_group system call. A -+ tracing engine can prevent a thread from beginning the exit or exec or -+ dying by signal (other than SIGKILL) if it is -+ attached to that thread, but once the operation begins, no tracing -+ engine can prevent or delay all other threads in the same thread group -+ dying. -+ -+ -+ -+ Final callbacks -+ -+ The report_reap callback is always the final event -+ in the life cycle of a traced thread. Tracing engines can use this as -+ the trigger to clean up their own data structures. The -+ report_death callback is always the penultimate -+ event a tracing engine might see; it's seen unless the thread was -+ already in the midst of dying when the engine attached. Many tracing -+ engines will have no interest in when a parent reaps a dead process, -+ and nothing they want to do with a zombie thread once it dies; for -+ them, the report_death callback is the natural -+ place to clean up data structures and detach. To facilitate writing -+ such engines robustly, given the asynchrony of -+ SIGKILL, and without error-prone manual -+ implementation of synchronization schemes, the -+ utrace infrastructure provides some special -+ guarantees about the report_death and -+ report_reap callbacks. It still takes some care -+ to be sure your tracing engine is robust to tear-down races, but these -+ rules make it reasonably straightforward and concise to handle a lot of -+ corner cases correctly. -+ -+ -+ -+ Engine and task pointers -+ -+ The first sort of guarantee concerns the core data structures -+ themselves. struct utrace_engine is -+ a reference-counted data structure. While you hold a reference, an -+ engine pointer will always stay valid so that you can safely pass it to -+ any utrace call. Each call to -+ utrace_attach_task or -+ utrace_attach_pid returns an engine pointer with a -+ reference belonging to the caller. You own that reference until you -+ drop it using utrace_engine_put. There is an -+ implicit reference on the engine while it is attached. So if you drop -+ your only reference, and then use -+ utrace_attach_task without -+ UTRACE_ATTACH_CREATE to look up that same engine, -+ you will get the same pointer with a new reference to replace the one -+ you dropped, just like calling utrace_engine_get. -+ When an engine has been detached, either explicitly with -+ UTRACE_DETACH or implicitly after -+ report_reap, then any references you hold are all -+ that keep the old engine pointer alive. -+ -+ -+ -+ There is nothing a kernel module can do to keep a struct -+ task_struct alive outside of -+ rcu_read_lock. When the task dies and is reaped -+ by its parent (or itself), that structure can be freed so that any -+ dangling pointers you have stored become invalid. -+ utrace will not prevent this, but it can -+ help you detect it safely. By definition, a task that has been reaped -+ has had all its engines detached. All -+ utrace calls can be safely called on a -+ detached engine if the caller holds a reference on that engine pointer, -+ even if the task pointer passed in the call is invalid. All calls -+ return -ESRCH for a detached engine, which tells -+ you that the task pointer you passed could be invalid now. Since -+ utrace_control and -+ utrace_set_events do not block, you can call those -+ inside a rcu_read_lock section and be sure after -+ they don't return -ESRCH that the task pointer is -+ still valid until rcu_read_unlock. The -+ infrastructure never holds task references of its own. Though neither -+ rcu_read_lock nor any other lock is held while -+ making a callback, it's always guaranteed that the struct -+ task_struct and the struct -+ utrace_engine passed as arguments remain valid -+ until the callback function returns. -+ -+ -+ -+ The common means for safely holding task pointers that is available to -+ kernel modules is to use struct pid, which -+ permits put_pid from kernel modules. When using -+ that, the calls utrace_attach_pid, -+ utrace_control_pid, -+ utrace_set_events_pid, and -+ utrace_barrier_pid are available. -+ -+ -+ -+ -+ -+ Serialization of <constant>DEATH</constant> and <constant>REAP</constant> -+ -+ -+ The second guarantee is the serialization of -+ DEATH and REAP event -+ callbacks for a given thread. The actual reaping by the parent -+ (release_task call) can occur simultaneously -+ while the thread is still doing the final steps of dying, including -+ the report_death callback. If a tracing engine -+ has requested both DEATH and -+ REAP event reports, it's guaranteed that the -+ report_reap callback will not be made until -+ after the report_death callback has returned. -+ If the report_death callback itself detaches -+ from the thread, then the report_reap callback -+ will never be made. Thus it is safe for a -+ report_death callback to clean up data -+ structures and detach. -+ -+ -+ -+ Interlock with final callbacks -+ -+ The final sort of guarantee is that a tracing engine will know for sure -+ whether or not the report_death and/or -+ report_reap callbacks will be made for a certain -+ thread. These tear-down races are disambiguated by the error return -+ values of utrace_set_events and -+ utrace_control. Normally -+ utrace_control called with -+ UTRACE_DETACH returns zero, and this means that no -+ more callbacks will be made. If the thread is in the midst of dying, -+ it returns -EALREADY to indicate that the -+ report_death callback may already be in progress; -+ when you get this error, you know that any cleanup your -+ report_death callback does is about to happen or -+ has just happened--note that if the report_death -+ callback does not detach, the engine remains attached until the thread -+ gets reaped. If the thread is in the midst of being reaped, -+ utrace_control returns -ESRCH -+ to indicate that the report_reap callback may -+ already be in progress; this means the engine is implicitly detached -+ when the callback completes. This makes it possible for a tracing -+ engine that has decided asynchronously to detach from a thread to -+ safely clean up its data structures, knowing that no -+ report_death or report_reap -+ callback will try to do the same. utrace_detach -+ returns -ESRCH when the struct -+ utrace_engine has already been detached, but is -+ still a valid pointer because of its reference count. A tracing engine -+ can use this to safely synchronize its own independent multiple threads -+ of control with each other and with its event callbacks that detach. -+ -+ -+ -+ In the same vein, utrace_set_events normally -+ returns zero; if the target thread was stopped before the call, then -+ after a successful call, no event callbacks not requested in the new -+ flags will be made. It fails with -EALREADY if -+ you try to clear UTRACE_EVENT(DEATH) when the -+ report_death callback may already have begun, or if -+ you try to newly set UTRACE_EVENT(DEATH) or -+ UTRACE_EVENT(QUIESCE) when the target is already -+ dead or dying. Like utrace_control, it returns -+ -ESRCH when the report_reap -+ callback may already have begun, or the thread has already been detached -+ (including forcible detach on reaping). This lets the tracing engine -+ know for sure which event callbacks it will or won't see after -+ utrace_set_events has returned. By checking for -+ errors, it can know whether to clean up its data structures immediately -+ or to let its callbacks do the work. -+ -+ -+ -+ Using <function>utrace_barrier</function> -+ -+ When a thread is safely stopped, calling -+ utrace_control with UTRACE_DETACH -+ or calling utrace_set_events to disable some events -+ ensures synchronously that your engine won't get any more of the callbacks -+ that have been disabled (none at all when detaching). But these can also -+ be used while the thread is not stopped, when it might be simultaneously -+ making a callback to your engine. For this situation, these calls return -+ -EINPROGRESS when it's possible a callback is in -+ progress. If you are not prepared to have your old callbacks still run, -+ then you can synchronize to be sure all the old callbacks are finished, -+ using utrace_barrier. This is necessary if the -+ kernel module containing your callback code is going to be unloaded. -+ -+ -+ After using UTRACE_DETACH once, further calls to -+ utrace_control with the same engine pointer will -+ return -ESRCH. In contrast, after getting -+ -EINPROGRESS from -+ utrace_set_events, you can call -+ utrace_set_events again later and if it returns zero -+ then know the old callbacks have finished. -+ -+ -+ Unlike all other calls, utrace_barrier (and -+ utrace_barrier_pid) will accept any engine pointer you -+ hold a reference on, even if UTRACE_DETACH has already -+ been used. After any utrace_control or -+ utrace_set_events call (these do not block), you can -+ call utrace_barrier to block until callbacks have -+ finished. This returns -ESRCH only if the engine is -+ completely detached (finished all callbacks). Otherwise it waits -+ until the thread is definitely not in the midst of a callback to this -+ engine and then returns zero, but can return -+ -ERESTARTSYS if its wait is interrupted. -+ -+ -+ -+ -+ -+ -+ -+utrace core API -+ -+ -+ The utrace API is declared in <linux/utrace.h>. -+ -+ -+!Iinclude/linux/utrace.h -+!Ekernel/utrace.c -+ -+ -+ -+Machine State -+ -+ -+ The task_current_syscall function can be used on any -+ valid struct task_struct at any time, and does -+ not even require that utrace_attach_task was used at all. -+ -+ -+ -+ The other ways to access the registers and other machine-dependent state of -+ a task can only be used on a task that is at a known safe point. The safe -+ points are all the places where utrace_set_events can -+ request callbacks (except for the DEATH and -+ REAP events). So at any event callback, it is safe to -+ examine current. -+ -+ -+ -+ One task can examine another only after a callback in the target task that -+ returns UTRACE_STOP so that task will not return to user -+ mode after the safe point. This guarantees that the task will not resume -+ until the same engine uses utrace_control, unless the -+ task dies suddenly. To examine safely, one must use a pair of calls to -+ utrace_prepare_examine and -+ utrace_finish_examine surrounding the calls to -+ struct user_regset functions or direct examination -+ of task data structures. utrace_prepare_examine returns -+ an error if the task is not properly stopped, or is dead. After a -+ successful examination, the paired utrace_finish_examine -+ call returns an error if the task ever woke up during the examination. If -+ so, any data gathered may be scrambled and should be discarded. This means -+ there was a spurious wake-up (which should not happen), or a sudden death. -+ -+ -+<structname>struct user_regset</structname> -+ -+ -+ The struct user_regset API -+ is declared in <linux/regset.h>. -+ -+ -+!Finclude/linux/regset.h -+ -+ -+ -+ -+ <filename>System Call Information</filename> -+ -+ -+ This function is declared in <linux/ptrace.h>. -+ -+ -+!Elib/syscall.c -+ -+ -+ -+<filename>System Call Tracing</filename> -+ -+ -+ The arch API for system call information is declared in -+ <asm/syscall.h>. -+ Each of these calls can be used only at system call entry tracing, -+ or can be used only at system call exit and the subsequent safe points -+ before returning to user mode. -+ At system call entry tracing means either during a -+ report_syscall_entry callback, -+ or any time after that callback has returned UTRACE_STOP. -+ -+ -+!Finclude/asm-generic/syscall.h -+ -+ -+ -+ -+ -+Kernel Internals -+ -+ -+ This chapter covers the interface to the tracing infrastructure -+ from the core of the kernel and the architecture-specific code. -+ This is for maintainers of the kernel and arch code, and not relevant -+ to using the tracing facilities described in preceding chapters. -+ -+ -+Core Calls In -+ -+ -+ These calls are declared in <linux/tracehook.h>. -+ The core kernel calls these functions at various important places. -+ -+ -+!Finclude/linux/tracehook.h -+ -+ -+ -+Architecture Calls Out -+ -+ -+ An arch that has done all these things sets -+ CONFIG_HAVE_ARCH_TRACEHOOK. -+ This is required to enable the utrace code. -+ -+ -+<filename><asm/ptrace.h></filename> -+ -+ -+ An arch defines these in <asm/ptrace.h> -+ if it supports hardware single-step or block-step features. -+ -+ -+!Finclude/linux/ptrace.h arch_has_single_step arch_has_block_step -+!Finclude/linux/ptrace.h user_enable_single_step user_enable_block_step -+!Finclude/linux/ptrace.h user_disable_single_step -+ -+ -+ -+ -+ <filename><asm/syscall.h></filename> -+ -+ -+ An arch provides <asm/syscall.h> that -+ defines these as inlines, or declares them as exported functions. -+ These interfaces are described in . -+ -+ -+ -+ -+ -+ <filename><linux/tracehook.h></filename> -+ -+ -+ An arch must define TIF_NOTIFY_RESUME -+ and TIF_SYSCALL_TRACE -+ in its <asm/thread_info.h>. -+ The arch code must call the following functions, all declared -+ in <linux/tracehook.h> and -+ described in : -+ -+ -+ -+ tracehook_notify_resume -+ -+ -+ tracehook_report_syscall_entry -+ -+ -+ tracehook_report_syscall_exit -+ -+ -+ tracehook_signal_handler -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/fs/proc/array.c b/fs/proc/array.c -index 9b45ee8..496fef3 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -81,6 +81,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -192,6 +193,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, - cred->uid, cred->euid, cred->suid, cred->fsuid, - cred->gid, cred->egid, cred->sgid, cred->fsgid); - -+ task_utrace_proc_status(m, p); -+ - task_lock(p); - if (p->files) - fdt = files_fdtable(p->files); -diff --git a/include/linux/sched.h b/include/linux/sched.h -index a837b20..b87de83 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1397,6 +1397,11 @@ struct task_struct { - #endif - seccomp_t seccomp; - -+#ifdef CONFIG_UTRACE -+ struct utrace *utrace; -+ unsigned long utrace_flags; -+#endif -+ - /* Thread group tracking */ - u32 parent_exec_id; - u32 self_exec_id; -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index e95f523..7d7bdde 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - struct linux_binprm; - - /** -@@ -63,6 +64,8 @@ struct linux_binprm; - */ - static inline int tracehook_expect_breakpoints(struct task_struct *task) - { -+ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_CORE))) -+ return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } - -@@ -111,6 +114,9 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - static inline __must_check int tracehook_report_syscall_entry( - struct pt_regs *regs) - { -+ if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && -+ utrace_report_syscall_entry(regs)) -+ return 1; - ptrace_report_syscall(regs); - return 0; - } -@@ -134,6 +140,9 @@ static inline __must_check int tracehook_report_syscall_entry( - */ - static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - { -+ if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) -+ utrace_report_syscall_exit(regs); -+ - if (step) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); -@@ -201,6 +210,8 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt, - struct linux_binprm *bprm, - struct pt_regs *regs) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXEC))) -+ utrace_report_exec(fmt, bprm, regs); - if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && - unlikely(task_ptrace(current) & PT_PTRACED)) - send_sig(SIGTRAP, current, 0); -@@ -218,10 +229,37 @@ static inline void tracehook_report_exec(struct linux_binfmt *fmt, - */ - static inline void tracehook_report_exit(long *exit_code) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT))) -+ utrace_report_exit(exit_code); - ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); - } - - /** -+ * tracehook_init_task - task_struct has just been copied -+ * @task: new &struct task_struct just copied from parent -+ * -+ * Called from do_fork() when @task has just been duplicated. -+ * After this, @task will be passed to tracehook_free_task() -+ * even if the rest of its setup fails before it is fully created. -+ */ -+static inline void tracehook_init_task(struct task_struct *task) -+{ -+ utrace_init_task(task); -+} -+ -+/** -+ * tracehook_free_task - task_struct is being freed -+ * @task: dead &struct task_struct being freed -+ * -+ * Called from free_task() when @task is no longer in use. -+ */ -+static inline void tracehook_free_task(struct task_struct *task) -+{ -+ if (task_utrace_struct(task)) -+ utrace_free_task(task); -+} -+ -+/** - * tracehook_prepare_clone - prepare for new child to be cloned - * @clone_flags: %CLONE_* flags from clone/fork/vfork system call - * -@@ -285,6 +323,8 @@ static inline void tracehook_report_clone(struct pt_regs *regs, - unsigned long clone_flags, - pid_t pid, struct task_struct *child) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE))) -+ utrace_report_clone(clone_flags, child); - if (unlikely(task_ptrace(child))) { - /* - * It doesn't matter who attached/attaching to this -@@ -317,6 +357,9 @@ static inline void tracehook_report_clone_complete(int trace, - pid_t pid, - struct task_struct *child) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE)) && -+ (clone_flags & CLONE_VFORK)) -+ utrace_finish_vfork(current); - if (unlikely(trace)) - ptrace_event(0, trace, pid); - } -@@ -351,6 +394,10 @@ static inline void tracehook_report_vfork_done(struct task_struct *child, - */ - static inline void tracehook_prepare_release_task(struct task_struct *task) - { -+ /* see utrace_add_engine() about this barrier */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_maybe_reap(task, task_utrace_struct(task), true); - } - - /** -@@ -365,6 +412,7 @@ static inline void tracehook_prepare_release_task(struct task_struct *task) - static inline void tracehook_finish_release_task(struct task_struct *task) - { - ptrace_release_task(task); -+ BUG_ON(task->exit_state != EXIT_DEAD); - } - - /** -@@ -386,6 +434,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - const struct k_sigaction *ka, - struct pt_regs *regs, int stepping) - { -+ if (task_utrace_flags(current)) -+ utrace_signal_handler(current, stepping); - if (stepping) - ptrace_notify(SIGTRAP); - } -@@ -403,6 +453,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - static inline int tracehook_consider_ignored_signal(struct task_struct *task, - int sig) - { -+ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_IGN))) -+ return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } - -@@ -422,6 +474,9 @@ static inline int tracehook_consider_ignored_signal(struct task_struct *task, - static inline int tracehook_consider_fatal_signal(struct task_struct *task, - int sig) - { -+ if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | -+ UTRACE_EVENT(SIGNAL_CORE)))) -+ return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } - -@@ -436,6 +491,8 @@ static inline int tracehook_consider_fatal_signal(struct task_struct *task, - */ - static inline int tracehook_force_sigpending(void) - { -+ if (unlikely(task_utrace_flags(current))) -+ return utrace_interrupt_pending(); - return 0; - } - -@@ -465,6 +522,8 @@ static inline int tracehook_get_signal(struct task_struct *task, - siginfo_t *info, - struct k_sigaction *return_ka) - { -+ if (unlikely(task_utrace_flags(task))) -+ return utrace_get_signal(task, regs, info, return_ka); - return 0; - } - -@@ -475,6 +534,8 @@ static inline int tracehook_get_signal(struct task_struct *task, - */ - static inline void tracehook_finish_jctl(void) - { -+ if (task_utrace_flags(current)) -+ utrace_finish_stop(); - } - - #define DEATH_REAP -1 -@@ -497,6 +558,8 @@ static inline void tracehook_finish_jctl(void) - static inline int tracehook_notify_death(struct task_struct *task, - void **death_cookie, int group_dead) - { -+ *death_cookie = task_utrace_struct(task); -+ - if (task_detached(task)) - return task->ptrace ? SIGCHLD : DEATH_REAP; - -@@ -533,6 +596,15 @@ static inline void tracehook_report_death(struct task_struct *task, - int signal, void *death_cookie, - int group_dead) - { -+ /* -+ * If utrace_set_events() was just called to enable -+ * UTRACE_EVENT(DEATH), then we are obliged to call -+ * utrace_report_death() and not miss it. utrace_set_events() -+ * checks @task->exit_state under tasklist_lock to synchronize -+ * with exit_notify(), the caller. -+ */ -+ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) -+ utrace_report_death(task, death_cookie, group_dead, signal); - } - - #ifdef TIF_NOTIFY_RESUME -@@ -562,10 +634,21 @@ static inline void set_notify_resume(struct task_struct *task) - * asynchronously, this will be called again before we return to - * user mode. - * -- * Called without locks. -+ * Called without locks. However, on some machines this may be -+ * called with interrupts disabled. - */ - static inline void tracehook_notify_resume(struct pt_regs *regs) - { -+ struct task_struct *task = current; -+ /* -+ * Prevent the following store/load from getting ahead of the -+ * caller which clears TIF_NOTIFY_RESUME. This pairs with the -+ * implicit mb() before setting TIF_NOTIFY_RESUME in -+ * set_notify_resume(). -+ */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_resume(task, regs); - } - #endif /* TIF_NOTIFY_RESUME */ - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -new file mode 100644 -index 0000000..f251efe ---- /dev/null -+++ b/include/linux/utrace.h -@@ -0,0 +1,692 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ * -+ * This interface allows for notification of interesting events in a -+ * thread. It also mediates access to thread state such as registers. -+ * Multiple unrelated users can be associated with a single thread. -+ * We call each of these a tracing engine. -+ * -+ * A tracing engine starts by calling utrace_attach_task() or -+ * utrace_attach_pid() on the chosen thread, passing in a set of hooks -+ * (&struct utrace_engine_ops), and some associated data. This produces a -+ * &struct utrace_engine, which is the handle used for all other -+ * operations. An attached engine has its ops vector, its data, and an -+ * event mask controlled by utrace_set_events(). -+ * -+ * For each event bit that is set, that engine will get the -+ * appropriate ops->report_*() callback when the event occurs. The -+ * &struct utrace_engine_ops need not provide callbacks for an event -+ * unless the engine sets one of the associated event bits. -+ */ -+ -+#ifndef _LINUX_UTRACE_H -+#define _LINUX_UTRACE_H 1 -+ -+#include -+#include -+#include -+#include -+ -+struct linux_binprm; -+struct pt_regs; -+struct utrace; -+struct user_regset; -+struct user_regset_view; -+ -+/* -+ * Event bits passed to utrace_set_events(). -+ * These appear in &struct task_struct.@utrace_flags -+ * and &struct utrace_engine.@flags. -+ */ -+enum utrace_events { -+ _UTRACE_EVENT_QUIESCE, /* Thread is available for examination. */ -+ _UTRACE_EVENT_REAP, /* Zombie reaped, no more tracing possible. */ -+ _UTRACE_EVENT_CLONE, /* Successful clone/fork/vfork just done. */ -+ _UTRACE_EVENT_EXEC, /* Successful execve just completed. */ -+ _UTRACE_EVENT_EXIT, /* Thread exit in progress. */ -+ _UTRACE_EVENT_DEATH, /* Thread has died. */ -+ _UTRACE_EVENT_SYSCALL_ENTRY, /* User entered kernel for system call. */ -+ _UTRACE_EVENT_SYSCALL_EXIT, /* Returning to user after system call. */ -+ _UTRACE_EVENT_SIGNAL, /* Signal delivery will run a user handler. */ -+ _UTRACE_EVENT_SIGNAL_IGN, /* No-op signal to be delivered. */ -+ _UTRACE_EVENT_SIGNAL_STOP, /* Signal delivery will suspend. */ -+ _UTRACE_EVENT_SIGNAL_TERM, /* Signal delivery will terminate. */ -+ _UTRACE_EVENT_SIGNAL_CORE, /* Signal delivery will dump core. */ -+ _UTRACE_EVENT_JCTL, /* Job control stop or continue completed. */ -+ _UTRACE_NEVENTS -+}; -+#define UTRACE_EVENT(type) (1UL << _UTRACE_EVENT_##type) -+ -+/* -+ * All the kinds of signal events. -+ * These all use the @report_signal() callback. -+ */ -+#define UTRACE_EVENT_SIGNAL_ALL (UTRACE_EVENT(SIGNAL) \ -+ | UTRACE_EVENT(SIGNAL_IGN) \ -+ | UTRACE_EVENT(SIGNAL_STOP) \ -+ | UTRACE_EVENT(SIGNAL_TERM) \ -+ | UTRACE_EVENT(SIGNAL_CORE)) -+/* -+ * Both kinds of syscall events; these call the @report_syscall_entry() -+ * and @report_syscall_exit() callbacks, respectively. -+ */ -+#define UTRACE_EVENT_SYSCALL \ -+ (UTRACE_EVENT(SYSCALL_ENTRY) | UTRACE_EVENT(SYSCALL_EXIT)) -+ -+/* -+ * The event reports triggered synchronously by task death. -+ */ -+#define _UTRACE_DEATH_EVENTS (UTRACE_EVENT(DEATH) | UTRACE_EVENT(QUIESCE)) -+ -+/* -+ * Hooks in call these entry points to the utrace dispatch. -+ */ -+void utrace_free_task(struct task_struct *); -+bool utrace_interrupt_pending(void); -+void utrace_resume(struct task_struct *, struct pt_regs *); -+void utrace_finish_stop(void); -+void utrace_maybe_reap(struct task_struct *, struct utrace *, bool); -+int utrace_get_signal(struct task_struct *, struct pt_regs *, -+ siginfo_t *, struct k_sigaction *); -+void utrace_report_clone(unsigned long, struct task_struct *); -+void utrace_finish_vfork(struct task_struct *); -+void utrace_report_exit(long *exit_code); -+void utrace_report_death(struct task_struct *, struct utrace *, bool, int); -+void utrace_report_jctl(int notify, int type); -+void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, -+ struct pt_regs *regs); -+bool utrace_report_syscall_entry(struct pt_regs *); -+void utrace_report_syscall_exit(struct pt_regs *); -+void utrace_signal_handler(struct task_struct *, int); -+ -+#ifndef CONFIG_UTRACE -+ -+/* -+ * uses these accessors to avoid #ifdef CONFIG_UTRACE. -+ */ -+static inline unsigned long task_utrace_flags(struct task_struct *task) -+{ -+ return 0; -+} -+static inline struct utrace *task_utrace_struct(struct task_struct *task) -+{ -+ return NULL; -+} -+static inline void utrace_init_task(struct task_struct *child) -+{ -+} -+ -+static inline void task_utrace_proc_status(struct seq_file *m, -+ struct task_struct *p) -+{ -+} -+ -+#else /* CONFIG_UTRACE */ -+ -+static inline unsigned long task_utrace_flags(struct task_struct *task) -+{ -+ return task->utrace_flags; -+} -+ -+static inline struct utrace *task_utrace_struct(struct task_struct *task) -+{ -+ struct utrace *utrace; -+ -+ /* -+ * This barrier ensures that any prior load of task->utrace_flags -+ * is ordered before this load of task->utrace. We use those -+ * utrace_flags checks in the hot path to decide to call into -+ * the utrace code. The first attach installs task->utrace before -+ * setting task->utrace_flags nonzero with implicit barrier in -+ * between, see utrace_add_engine(). -+ */ -+ smp_rmb(); -+ utrace = task->utrace; -+ -+ smp_read_barrier_depends(); /* See utrace_task_alloc(). */ -+ return utrace; -+} -+ -+static inline void utrace_init_task(struct task_struct *task) -+{ -+ task->utrace_flags = 0; -+ task->utrace = NULL; -+} -+ -+void task_utrace_proc_status(struct seq_file *m, struct task_struct *p); -+ -+ -+/* -+ * Version number of the API defined in this file. This will change -+ * whenever a tracing engine's code would need some updates to keep -+ * working. We maintain this here for the benefit of tracing engine code -+ * that is developed concurrently with utrace API improvements before they -+ * are merged into the kernel, making LINUX_VERSION_CODE checks unwieldy. -+ */ -+#define UTRACE_API_VERSION 20091216 -+ -+/** -+ * enum utrace_resume_action - engine's choice of action for a traced task -+ * @UTRACE_STOP: Stay quiescent after callbacks. -+ * @UTRACE_INTERRUPT: Make @report_signal() callback soon. -+ * @UTRACE_REPORT: Make some callback soon. -+ * @UTRACE_SINGLESTEP: Resume in user mode for one instruction. -+ * @UTRACE_BLOCKSTEP: Resume in user mode until next branch. -+ * @UTRACE_RESUME: Resume normally in user mode. -+ * @UTRACE_DETACH: Detach my engine (implies %UTRACE_RESUME). -+ * -+ * See utrace_control() for detailed descriptions of each action. This is -+ * encoded in the @action argument and the return value for every callback -+ * with a &u32 return value. -+ * -+ * The order of these is important. When there is more than one engine, -+ * each supplies its choice and the smallest value prevails. -+ */ -+enum utrace_resume_action { -+ UTRACE_STOP, -+ UTRACE_INTERRUPT, -+ UTRACE_REPORT, -+ UTRACE_SINGLESTEP, -+ UTRACE_BLOCKSTEP, -+ UTRACE_RESUME, -+ UTRACE_DETACH, -+ UTRACE_RESUME_MAX -+}; -+#define UTRACE_RESUME_BITS (ilog2(UTRACE_RESUME_MAX) + 1) -+#define UTRACE_RESUME_MASK ((1 << UTRACE_RESUME_BITS) - 1) -+ -+/** -+ * utrace_resume_action - &enum utrace_resume_action from callback action -+ * @action: &u32 callback @action argument or return value -+ * -+ * This extracts the &enum utrace_resume_action from @action, -+ * which is the @action argument to a &struct utrace_engine_ops -+ * callback or the return value from one. -+ */ -+static inline enum utrace_resume_action utrace_resume_action(u32 action) -+{ -+ return action & UTRACE_RESUME_MASK; -+} -+ -+/** -+ * enum utrace_signal_action - disposition of signal -+ * @UTRACE_SIGNAL_DELIVER: Deliver according to sigaction. -+ * @UTRACE_SIGNAL_IGN: Ignore the signal. -+ * @UTRACE_SIGNAL_TERM: Terminate the process. -+ * @UTRACE_SIGNAL_CORE: Terminate with core dump. -+ * @UTRACE_SIGNAL_STOP: Deliver as absolute stop. -+ * @UTRACE_SIGNAL_TSTP: Deliver as job control stop. -+ * @UTRACE_SIGNAL_REPORT: Reporting before pending signals. -+ * @UTRACE_SIGNAL_HANDLER: Reporting after signal handler setup. -+ * -+ * This is encoded in the @action argument and the return value for -+ * a @report_signal() callback. It says what will happen to the -+ * signal described by the &siginfo_t parameter to the callback. -+ * -+ * The %UTRACE_SIGNAL_REPORT value is used in an @action argument when -+ * a tracing report is being made before dequeuing any pending signal. -+ * If this is immediately after a signal handler has been set up, then -+ * %UTRACE_SIGNAL_HANDLER is used instead. A @report_signal callback -+ * that uses %UTRACE_SIGNAL_DELIVER|%UTRACE_SINGLESTEP will ensure -+ * it sees a %UTRACE_SIGNAL_HANDLER report. -+ */ -+enum utrace_signal_action { -+ UTRACE_SIGNAL_DELIVER = 0x00, -+ UTRACE_SIGNAL_IGN = 0x10, -+ UTRACE_SIGNAL_TERM = 0x20, -+ UTRACE_SIGNAL_CORE = 0x30, -+ UTRACE_SIGNAL_STOP = 0x40, -+ UTRACE_SIGNAL_TSTP = 0x50, -+ UTRACE_SIGNAL_REPORT = 0x60, -+ UTRACE_SIGNAL_HANDLER = 0x70 -+}; -+#define UTRACE_SIGNAL_MASK 0xf0 -+#define UTRACE_SIGNAL_HOLD 0x100 /* Flag, push signal back on queue. */ -+ -+/** -+ * utrace_signal_action - &enum utrace_signal_action from callback action -+ * @action: @report_signal callback @action argument or return value -+ * -+ * This extracts the &enum utrace_signal_action from @action, which -+ * is the @action argument to a @report_signal callback or the -+ * return value from one. -+ */ -+static inline enum utrace_signal_action utrace_signal_action(u32 action) -+{ -+ return action & UTRACE_SIGNAL_MASK; -+} -+ -+/** -+ * enum utrace_syscall_action - disposition of system call attempt -+ * @UTRACE_SYSCALL_RUN: Run the system call. -+ * @UTRACE_SYSCALL_ABORT: Don't run the system call. -+ * -+ * This is encoded in the @action argument and the return value for -+ * a @report_syscall_entry callback. -+ */ -+enum utrace_syscall_action { -+ UTRACE_SYSCALL_RUN = 0x00, -+ UTRACE_SYSCALL_ABORT = 0x10 -+}; -+#define UTRACE_SYSCALL_MASK 0xf0 -+#define UTRACE_SYSCALL_RESUMED 0x100 /* Flag, report_syscall_entry() repeats */ -+ -+/** -+ * utrace_syscall_action - &enum utrace_syscall_action from callback action -+ * @action: @report_syscall_entry callback @action or return value -+ * -+ * This extracts the &enum utrace_syscall_action from @action, which -+ * is the @action argument to a @report_syscall_entry callback or the -+ * return value from one. -+ */ -+static inline enum utrace_syscall_action utrace_syscall_action(u32 action) -+{ -+ return action & UTRACE_SYSCALL_MASK; -+} -+ -+/* -+ * Flags for utrace_attach_task() and utrace_attach_pid(). -+ */ -+#define UTRACE_ATTACH_MATCH_OPS 0x0001 /* Match engines on ops. */ -+#define UTRACE_ATTACH_MATCH_DATA 0x0002 /* Match engines on data. */ -+#define UTRACE_ATTACH_MATCH_MASK 0x000f -+#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */ -+#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */ -+ -+/** -+ * struct utrace_engine - per-engine structure -+ * @ops: &struct utrace_engine_ops pointer passed to utrace_attach_task() -+ * @data: engine-private &void * passed to utrace_attach_task() -+ * @flags: event mask set by utrace_set_events() plus internal flag bits -+ * -+ * The task itself never has to worry about engines detaching while -+ * it's doing event callbacks. These structures are removed from the -+ * task's active list only when it's stopped, or by the task itself. -+ * -+ * utrace_engine_get() and utrace_engine_put() maintain a reference count. -+ * When it drops to zero, the structure is freed. One reference is held -+ * implicitly while the engine is attached to its task. -+ */ -+struct utrace_engine { -+/* private: */ -+ struct kref kref; -+ void (*release)(void *); -+ struct list_head entry; -+ -+/* public: */ -+ const struct utrace_engine_ops *ops; -+ void *data; -+ -+ unsigned long flags; -+}; -+ -+/** -+ * utrace_engine_get - acquire a reference on a &struct utrace_engine -+ * @engine: &struct utrace_engine pointer -+ * -+ * You must hold a reference on @engine, and you get another. -+ */ -+static inline void utrace_engine_get(struct utrace_engine *engine) -+{ -+ kref_get(&engine->kref); -+} -+ -+void __utrace_engine_release(struct kref *); -+ -+/** -+ * utrace_engine_put - release a reference on a &struct utrace_engine -+ * @engine: &struct utrace_engine pointer -+ * -+ * You must hold a reference on @engine, and you lose that reference. -+ * If it was the last one, @engine becomes an invalid pointer. -+ */ -+static inline void utrace_engine_put(struct utrace_engine *engine) -+{ -+ kref_put(&engine->kref, __utrace_engine_release); -+} -+ -+/** -+ * struct utrace_engine_ops - tracing engine callbacks -+ * -+ * Each @report_*() callback corresponds to an %UTRACE_EVENT(*) bit. -+ * utrace_set_events() calls on @engine choose which callbacks will -+ * be made to @engine from @task. -+ * -+ * Most callbacks take an @action argument, giving the resume action -+ * chosen by other tracing engines. All callbacks take an @engine -+ * argument. The @report_reap callback takes a @task argument that -+ * might or might not be @current. All other @report_* callbacks -+ * report an event in the @current task. -+ * -+ * For some calls, @action also includes bits specific to that event -+ * and utrace_resume_action() is used to extract the resume action. -+ * This shows what would happen if @engine wasn't there, or will if -+ * the callback's return value uses %UTRACE_RESUME. This always -+ * starts as %UTRACE_RESUME when no other tracing is being done on -+ * this task. -+ * -+ * All return values contain &enum utrace_resume_action bits. For -+ * some calls, other bits specific to that kind of event are added to -+ * the resume action bits with OR. These are the same bits used in -+ * the @action argument. The resume action returned by a callback -+ * does not override previous engines' choices, it only says what -+ * @engine wants done. What @current actually does is the action that's -+ * most constrained among the choices made by all attached engines. -+ * See utrace_control() for more information on the actions. -+ * -+ * When %UTRACE_STOP is used in @report_syscall_entry, then @current -+ * stops before attempting the system call. In this case, another -+ * @report_syscall_entry callback will follow after @current resumes if -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT was returned by some callback -+ * or passed to utrace_control(). In a second or later callback, -+ * %UTRACE_SYSCALL_RESUMED is set in the @action argument to indicate -+ * a repeat callback still waiting to attempt the same system call -+ * invocation. This repeat callback gives each engine an opportunity -+ * to reexamine registers another engine might have changed while -+ * @current was held in %UTRACE_STOP. -+ * -+ * In other cases, the resume action does not take effect until @current -+ * is ready to check for signals and return to user mode. If there -+ * are more callbacks to be made, the last round of calls determines -+ * the final action. A @report_quiesce callback with @event zero, or -+ * a @report_signal callback, will always be the last one made before -+ * @current resumes. Only %UTRACE_STOP is "sticky"--if @engine returned -+ * %UTRACE_STOP then @current stays stopped unless @engine returns -+ * different from a following callback. -+ * -+ * The report_death() and report_reap() callbacks do not take @action -+ * arguments, and only %UTRACE_DETACH is meaningful in the return value -+ * from a report_death() callback. None of the resume actions applies -+ * to a dead thread. -+ * -+ * All @report_*() hooks are called with no locks held, in a generally -+ * safe environment when we will be returning to user mode soon (or just -+ * entered the kernel). It is fine to block for memory allocation and -+ * the like, but all hooks are asynchronous and must not block on -+ * external events! If you want the thread to block, use %UTRACE_STOP -+ * in your hook's return value; then later wake it up with utrace_control(). -+ * -+ * @report_quiesce: -+ * Requested by %UTRACE_EVENT(%QUIESCE). -+ * This does not indicate any event, but just that @current is in a -+ * safe place for examination. This call is made before each specific -+ * event callback, except for @report_reap. The @event argument gives -+ * the %UTRACE_EVENT(@which) value for the event occurring. This -+ * callback might be made for events @engine has not requested, if -+ * some other engine is tracing the event; calling utrace_set_events() -+ * call here can request the immediate callback for this occurrence of -+ * @event. @event is zero when there is no other event, @current is -+ * now ready to check for signals and return to user mode, and some -+ * engine has used %UTRACE_REPORT or %UTRACE_INTERRUPT to request this -+ * callback. For this case, if @report_signal is not %NULL, the -+ * @report_quiesce callback may be replaced with a @report_signal -+ * callback passing %UTRACE_SIGNAL_REPORT in its @action argument, -+ * whenever @current is entering the signal-check path anyway. -+ * -+ * @report_signal: -+ * Requested by %UTRACE_EVENT(%SIGNAL_*) or %UTRACE_EVENT(%QUIESCE). -+ * Use utrace_signal_action() and utrace_resume_action() on @action. -+ * The signal action is %UTRACE_SIGNAL_REPORT when some engine has -+ * used %UTRACE_REPORT or %UTRACE_INTERRUPT; the callback can choose -+ * to stop or to deliver an artificial signal, before pending signals. -+ * It's %UTRACE_SIGNAL_HANDLER instead when signal handler setup just -+ * finished (after a previous %UTRACE_SIGNAL_DELIVER return); this -+ * serves in lieu of any %UTRACE_SIGNAL_REPORT callback requested by -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT, and is also implicitly -+ * requested by %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP into the -+ * signal delivery. The other signal actions indicate a signal about -+ * to be delivered; the previous engine's return value sets the signal -+ * action seen by the the following engine's callback. The @info data -+ * can be changed at will, including @info->si_signo. The settings in -+ * @return_ka determines what %UTRACE_SIGNAL_DELIVER does. @orig_ka -+ * is what was in force before other tracing engines intervened, and -+ * it's %NULL when this report began as %UTRACE_SIGNAL_REPORT or -+ * %UTRACE_SIGNAL_HANDLER. For a report without a new signal, @info -+ * is left uninitialized and must be set completely by an engine that -+ * chooses to deliver a signal; if there was a previous @report_signal -+ * callback ending in %UTRACE_STOP and it was just resumed using -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT, then @info is left unchanged -+ * from the previous callback. In this way, the original signal can -+ * be left in @info while returning %UTRACE_STOP|%UTRACE_SIGNAL_IGN -+ * and then found again when resuming with %UTRACE_INTERRUPT. -+ * The %UTRACE_SIGNAL_HOLD flag bit can be OR'd into the return value, -+ * and might be in @action if the previous engine returned it. This -+ * flag asks that the signal in @info be pushed back on @current's queue -+ * so that it will be seen again after whatever action is taken now. -+ * -+ * @report_clone: -+ * Requested by %UTRACE_EVENT(%CLONE). -+ * Event reported for parent, before the new task @child might run. -+ * @clone_flags gives the flags used in the clone system call, or -+ * equivalent flags for a fork() or vfork() system call. This -+ * function can use utrace_attach_task() on @child. Then passing -+ * %UTRACE_STOP to utrace_control() on @child here keeps the child -+ * stopped before it ever runs in user mode, %UTRACE_REPORT or -+ * %UTRACE_INTERRUPT ensures a callback from @child before it -+ * starts in user mode. -+ * -+ * @report_jctl: -+ * Requested by %UTRACE_EVENT(%JCTL). -+ * Job control event; @type is %CLD_STOPPED or %CLD_CONTINUED, -+ * indicating whether we are stopping or resuming now. If @notify -+ * is nonzero, @current is the last thread to stop and so will send -+ * %SIGCHLD to its parent after this callback; @notify reflects -+ * what the parent's %SIGCHLD has in @si_code, which can sometimes -+ * be %CLD_STOPPED even when @type is %CLD_CONTINUED. -+ * -+ * @report_exec: -+ * Requested by %UTRACE_EVENT(%EXEC). -+ * An execve system call has succeeded and the new program is about to -+ * start running. The initial user register state is handy to be tweaked -+ * directly in @regs. @fmt and @bprm gives the details of this exec. -+ * -+ * @report_syscall_entry: -+ * Requested by %UTRACE_EVENT(%SYSCALL_ENTRY). -+ * Thread has entered the kernel to request a system call. -+ * The user register state is handy to be tweaked directly in @regs. -+ * The @action argument contains an &enum utrace_syscall_action, -+ * use utrace_syscall_action() to extract it. The return value -+ * overrides the last engine's action for the system call. -+ * If the final action is %UTRACE_SYSCALL_ABORT, no system call -+ * is made. The details of the system call being attempted can -+ * be fetched here with syscall_get_nr() and syscall_get_arguments(). -+ * The parameter registers can be changed with syscall_set_arguments(). -+ * See above about the %UTRACE_SYSCALL_RESUMED flag in @action. -+ * Use %UTRACE_REPORT in the return value to guarantee you get -+ * another callback (with %UTRACE_SYSCALL_RESUMED flag) in case -+ * @current stops with %UTRACE_STOP before attempting the system call. -+ * -+ * @report_syscall_exit: -+ * Requested by %UTRACE_EVENT(%SYSCALL_EXIT). -+ * Thread is about to leave the kernel after a system call request. -+ * The user register state is handy to be tweaked directly in @regs. -+ * The results of the system call attempt can be examined here using -+ * syscall_get_error() and syscall_get_return_value(). It is safe -+ * here to call syscall_set_return_value() or syscall_rollback(). -+ * -+ * @report_exit: -+ * Requested by %UTRACE_EVENT(%EXIT). -+ * Thread is exiting and cannot be prevented from doing so, -+ * but all its state is still live. The @code value will be -+ * the wait result seen by the parent, and can be changed by -+ * this engine or others. The @orig_code value is the real -+ * status, not changed by any tracing engine. Returning %UTRACE_STOP -+ * here keeps @current stopped before it cleans up its state and dies, -+ * so it can be examined by other processes. When @current is allowed -+ * to run, it will die and get to the @report_death callback. -+ * -+ * @report_death: -+ * Requested by %UTRACE_EVENT(%DEATH). -+ * Thread is really dead now. It might be reaped by its parent at -+ * any time, or self-reap immediately. Though the actual reaping -+ * may happen in parallel, a report_reap() callback will always be -+ * ordered after a report_death() callback. -+ * -+ * @report_reap: -+ * Requested by %UTRACE_EVENT(%REAP). -+ * Called when someone reaps the dead task (parent, init, or self). -+ * This means the parent called wait, or else this was a detached -+ * thread or a process whose parent ignores SIGCHLD. -+ * No more callbacks are made after this one. -+ * The engine is always detached. -+ * There is nothing more a tracing engine can do about this thread. -+ * After this callback, the @engine pointer will become invalid. -+ * The @task pointer may become invalid if get_task_struct() hasn't -+ * been used to keep it alive. -+ * An engine should always request this callback if it stores the -+ * @engine pointer or stores any pointer in @engine->data, so it -+ * can clean up its data structures. -+ * Unlike other callbacks, this can be called from the parent's context -+ * rather than from the traced thread itself--it must not delay the -+ * parent by blocking. -+ * -+ * @release: -+ * If not %NULL, this is called after the last utrace_engine_put() -+ * call for a &struct utrace_engine, which could be implicit after -+ * a %UTRACE_DETACH return from another callback. Its argument is -+ * the engine's @data member. -+ */ -+struct utrace_engine_ops { -+ u32 (*report_quiesce)(u32 action, struct utrace_engine *engine, -+ unsigned long event); -+ u32 (*report_signal)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs, -+ siginfo_t *info, -+ const struct k_sigaction *orig_ka, -+ struct k_sigaction *return_ka); -+ u32 (*report_clone)(u32 action, struct utrace_engine *engine, -+ unsigned long clone_flags, -+ struct task_struct *child); -+ u32 (*report_jctl)(u32 action, struct utrace_engine *engine, -+ int type, int notify); -+ u32 (*report_exec)(u32 action, struct utrace_engine *engine, -+ const struct linux_binfmt *fmt, -+ const struct linux_binprm *bprm, -+ struct pt_regs *regs); -+ u32 (*report_syscall_entry)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs); -+ u32 (*report_syscall_exit)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs); -+ u32 (*report_exit)(u32 action, struct utrace_engine *engine, -+ long orig_code, long *code); -+ u32 (*report_death)(struct utrace_engine *engine, -+ bool group_dead, int signal); -+ void (*report_reap)(struct utrace_engine *engine, -+ struct task_struct *task); -+ void (*release)(void *data); -+}; -+ -+/** -+ * struct utrace_examiner - private state for using utrace_prepare_examine() -+ * -+ * The members of &struct utrace_examiner are private to the implementation. -+ * This data type holds the state from a call to utrace_prepare_examine() -+ * to be used by a call to utrace_finish_examine(). -+ */ -+struct utrace_examiner { -+/* private: */ -+ long state; -+ unsigned long ncsw; -+}; -+ -+/* -+ * These are the exported entry points for tracing engines to use. -+ * See kernel/utrace.c for their kerneldoc comments with interface details. -+ */ -+struct utrace_engine *utrace_attach_task(struct task_struct *, int, -+ const struct utrace_engine_ops *, -+ void *); -+struct utrace_engine *utrace_attach_pid(struct pid *, int, -+ const struct utrace_engine_ops *, -+ void *); -+int __must_check utrace_control(struct task_struct *, -+ struct utrace_engine *, -+ enum utrace_resume_action); -+int __must_check utrace_set_events(struct task_struct *, -+ struct utrace_engine *, -+ unsigned long eventmask); -+int __must_check utrace_barrier(struct task_struct *, -+ struct utrace_engine *); -+int __must_check utrace_prepare_examine(struct task_struct *, -+ struct utrace_engine *, -+ struct utrace_examiner *); -+int __must_check utrace_finish_examine(struct task_struct *, -+ struct utrace_engine *, -+ struct utrace_examiner *); -+ -+/** -+ * utrace_control_pid - control a thread being traced by a tracing engine -+ * @pid: thread to affect -+ * @engine: attached engine to affect -+ * @action: &enum utrace_resume_action for thread to do -+ * -+ * This is the same as utrace_control(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_control_pid( -+ struct pid *pid, struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ /* -+ * We don't bother with rcu_read_lock() here to protect the -+ * task_struct pointer, because utrace_control will return -+ * -ESRCH without looking at that pointer if the engine is -+ * already detached. A task_struct pointer can't die before -+ * all the engines are detached in release_task() first. -+ */ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : utrace_control(task, engine, action); -+} -+ -+/** -+ * utrace_set_events_pid - choose which event reports a tracing engine gets -+ * @pid: thread to affect -+ * @engine: attached engine to affect -+ * @eventmask: new event mask -+ * -+ * This is the same as utrace_set_events(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_set_events_pid( -+ struct pid *pid, struct utrace_engine *engine, unsigned long eventmask) -+{ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : -+ utrace_set_events(task, engine, eventmask); -+} -+ -+/** -+ * utrace_barrier_pid - synchronize with simultaneous tracing callbacks -+ * @pid: thread to affect -+ * @engine: engine to affect (can be detached) -+ * -+ * This is the same as utrace_barrier(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_barrier_pid(struct pid *pid, -+ struct utrace_engine *engine) -+{ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : utrace_barrier(task, engine); -+} -+ -+#endif /* CONFIG_UTRACE */ -+ -+#endif /* linux/utrace.h */ -diff --git a/init/Kconfig b/init/Kconfig -index 412c21b..a03ae51 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -372,6 +372,15 @@ config AUDIT_TREE - depends on AUDITSYSCALL - select FSNOTIFY - -+config UTRACE -+ bool "Infrastructure for tracing and debugging user processes" -+ depends on EXPERIMENTAL -+ depends on HAVE_ARCH_TRACEHOOK -+ help -+ Enable the utrace process tracing interface. This is an internal -+ kernel interface exported to kernel modules, to track events in -+ user threads, extract and change user thread state. -+ - source "kernel/irq/Kconfig" - - menu "RCU Subsystem" -diff --git a/kernel/Makefile b/kernel/Makefile -index 2d64cfc..4a22e81 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -68,6 +68,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o - obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o - obj-$(CONFIG_SMP) += stop_machine.o - obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o -+obj-$(CONFIG_UTRACE) += utrace.o - obj-$(CONFIG_AUDIT) += audit.o auditfilter.o - obj-$(CONFIG_AUDITSYSCALL) += auditsc.o - obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o -diff --git a/kernel/fork.c b/kernel/fork.c -index 0276c30..62caf3d 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -168,6 +168,7 @@ void free_task(struct task_struct *tsk) - free_thread_info(tsk->stack); - rt_mutex_debug_task_free(tsk); - ftrace_graph_exit_task(tsk); -+ tracehook_free_task(tsk); - free_task_struct(tsk); - } - EXPORT_SYMBOL(free_task); -@@ -1095,6 +1096,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, - if (!p) - goto fork_out; - -+ tracehook_init_task(p); -+ - ftrace_graph_init_task(p); - - rt_mutex_init_task(p); -diff --git a/kernel/utrace.c b/kernel/utrace.c -new file mode 100644 -index 0000000..f332d65 ---- /dev/null -+++ b/kernel/utrace.c -@@ -0,0 +1,2440 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* -+ * Per-thread structure private to utrace implementation. -+ * If task_struct.utrace_flags is nonzero, task_struct.utrace -+ * has always been allocated first. Once allocated, it is -+ * never freed until free_task(). -+ * -+ * The common event reporting loops are done by the task making the -+ * report without ever taking any locks. To facilitate this, the two -+ * lists @attached and @attaching work together for smooth asynchronous -+ * attaching with low overhead. Modifying either list requires @lock. -+ * The @attaching list can be modified any time while holding @lock. -+ * New engines being attached always go on this list. -+ * -+ * The @attached list is what the task itself uses for its reporting -+ * loops. When the task itself is not quiescent, it can use the -+ * @attached list without taking any lock. Nobody may modify the list -+ * when the task is not quiescent. When it is quiescent, that means -+ * that it won't run again without taking @lock itself before using -+ * the list. -+ * -+ * At each place where we know the task is quiescent (or it's current), -+ * while holding @lock, we call splice_attaching(), below. This moves -+ * the @attaching list members on to the end of the @attached list. -+ * Since this happens at the start of any reporting pass, any new -+ * engines attached asynchronously go on the stable @attached list -+ * in time to have their callbacks seen. -+ */ -+struct utrace { -+ spinlock_t lock; -+ struct list_head attached, attaching; -+ -+ struct task_struct *cloning; -+ -+ struct utrace_engine *reporting; -+ -+ enum utrace_resume_action resume:UTRACE_RESUME_BITS; -+ unsigned int signal_handler:1; -+ unsigned int vfork_stop:1; /* need utrace_stop() before vfork wait */ -+ unsigned int death:1; /* in utrace_report_death() now */ -+ unsigned int reap:1; /* release_task() has run */ -+ unsigned int pending_attach:1; /* need splice_attaching() */ -+}; -+ -+static struct kmem_cache *utrace_cachep; -+static struct kmem_cache *utrace_engine_cachep; -+static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */ -+ -+static int __init utrace_init(void) -+{ -+ utrace_cachep = KMEM_CACHE(utrace, SLAB_PANIC); -+ utrace_engine_cachep = KMEM_CACHE(utrace_engine, SLAB_PANIC); -+ return 0; -+} -+module_init(utrace_init); -+ -+/* -+ * Set up @task.utrace for the first time. We can have races -+ * between two utrace_attach_task() calls here. The task_lock() -+ * governs installing the new pointer. If another one got in first, -+ * we just punt the new one we allocated. -+ * -+ * This returns false only in case of a memory allocation failure. -+ */ -+static bool utrace_task_alloc(struct task_struct *task) -+{ -+ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, GFP_KERNEL); -+ if (unlikely(!utrace)) -+ return false; -+ spin_lock_init(&utrace->lock); -+ INIT_LIST_HEAD(&utrace->attached); -+ INIT_LIST_HEAD(&utrace->attaching); -+ utrace->resume = UTRACE_RESUME; -+ task_lock(task); -+ if (likely(!task->utrace)) { -+ /* -+ * This barrier makes sure the initialization of the struct -+ * precedes the installation of the pointer. This pairs -+ * with smp_read_barrier_depends() in task_utrace_struct(). -+ */ -+ smp_wmb(); -+ task->utrace = utrace; -+ } -+ task_unlock(task); -+ -+ if (unlikely(task->utrace != utrace)) -+ kmem_cache_free(utrace_cachep, utrace); -+ return true; -+} -+ -+/* -+ * This is called via tracehook_free_task() from free_task() -+ * when @task is being deallocated. -+ */ -+void utrace_free_task(struct task_struct *task) -+{ -+ kmem_cache_free(utrace_cachep, task->utrace); -+} -+ -+/* -+ * This is calledwhen the task is safely quiescent, i.e. it won't consult -+ * utrace->attached without the lock. Move any engines attached -+ * asynchronously from @utrace->attaching onto the @utrace->attached list. -+ */ -+static void splice_attaching(struct utrace *utrace) -+{ -+ lockdep_assert_held(&utrace->lock); -+ list_splice_tail_init(&utrace->attaching, &utrace->attached); -+ utrace->pending_attach = 0; -+} -+ -+/* -+ * This is the exported function used by the utrace_engine_put() inline. -+ */ -+void __utrace_engine_release(struct kref *kref) -+{ -+ struct utrace_engine *engine = container_of(kref, struct utrace_engine, -+ kref); -+ BUG_ON(!list_empty(&engine->entry)); -+ if (engine->release) -+ (*engine->release)(engine->data); -+ kmem_cache_free(utrace_engine_cachep, engine); -+} -+EXPORT_SYMBOL_GPL(__utrace_engine_release); -+ -+static bool engine_matches(struct utrace_engine *engine, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops) -+ return false; -+ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data) -+ return false; -+ return engine->ops && engine->ops != &utrace_detached_ops; -+} -+ -+static struct utrace_engine *find_matching_engine( -+ struct utrace *utrace, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ list_for_each_entry(engine, &utrace->attaching, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ return NULL; -+} -+ -+/* -+ * Enqueue @engine, or maybe don't if UTRACE_ATTACH_EXCLUSIVE. -+ */ -+static int utrace_add_engine(struct task_struct *target, -+ struct utrace *utrace, -+ struct utrace_engine *engine, -+ int flags, -+ const struct utrace_engine_ops *ops, -+ void *data) -+{ -+ int ret; -+ -+ spin_lock(&utrace->lock); -+ -+ ret = -EEXIST; -+ if ((flags & UTRACE_ATTACH_EXCLUSIVE) && -+ unlikely(find_matching_engine(utrace, flags, ops, data))) -+ goto unlock; -+ -+ /* -+ * In case we had no engines before, make sure that -+ * utrace_flags is not zero. Since we did unlock+lock -+ * at least once after utrace_task_alloc() installed -+ * ->utrace, we have the necessary barrier which pairs -+ * with rmb() in task_utrace_struct(). -+ */ -+ ret = -ESRCH; -+ if (!target->utrace_flags) { -+ target->utrace_flags = UTRACE_EVENT(REAP); -+ /* -+ * If we race with tracehook_prepare_release_task() -+ * make sure that either it sees utrace_flags != 0 -+ * or we see exit_state == EXIT_DEAD. -+ */ -+ smp_mb(); -+ if (unlikely(target->exit_state == EXIT_DEAD)) { -+ target->utrace_flags = 0; -+ goto unlock; -+ } -+ } -+ -+ /* -+ * Put the new engine on the pending ->attaching list. -+ * Make sure it gets onto the ->attached list by the next -+ * time it's examined. Setting ->pending_attach ensures -+ * that start_report() takes the lock and splices the lists -+ * before the next new reporting pass. -+ * -+ * When target == current, it would be safe just to call -+ * splice_attaching() right here. But if we're inside a -+ * callback, that would mean the new engine also gets -+ * notified about the event that precipitated its own -+ * creation. This is not what the user wants. -+ */ -+ list_add_tail(&engine->entry, &utrace->attaching); -+ utrace->pending_attach = 1; -+ utrace_engine_get(engine); -+ ret = 0; -+unlock: -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+ -+/** -+ * utrace_attach_task - attach new engine, or look up an attached engine -+ * @target: thread to attach to -+ * @flags: flag bits combined with OR, see below -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * The caller must ensure that the @target thread does not get freed, -+ * i.e. hold a ref or be its parent. It is always safe to call this -+ * on @current, or on the @child pointer in a @report_clone callback. -+ * For most other cases, it's easier to use utrace_attach_pid() instead. -+ * -+ * UTRACE_ATTACH_CREATE: -+ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you -+ * only look up an existing engine already attached to the thread. -+ * -+ * UTRACE_ATTACH_EXCLUSIVE: -+ * Attempting to attach a second (matching) engine fails with -%EEXIST. -+ * -+ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops. -+ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data. -+ * -+ * Calls with neither %UTRACE_ATTACH_MATCH_OPS nor %UTRACE_ATTACH_MATCH_DATA -+ * match the first among any engines attached to @target. That means that -+ * %UTRACE_ATTACH_EXCLUSIVE in such a call fails with -%EEXIST if there -+ * are any engines on @target at all. -+ */ -+struct utrace_engine *utrace_attach_task( -+ struct task_struct *target, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace *utrace = task_utrace_struct(target); -+ struct utrace_engine *engine; -+ int ret; -+ -+ if (!(flags & UTRACE_ATTACH_CREATE)) { -+ if (unlikely(!utrace)) -+ return ERR_PTR(-ENOENT); -+ spin_lock(&utrace->lock); -+ engine = find_matching_engine(utrace, flags, ops, data); -+ if (engine) -+ utrace_engine_get(engine); -+ spin_unlock(&utrace->lock); -+ return engine ?: ERR_PTR(-ENOENT); -+ } -+ -+ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops)) -+ return ERR_PTR(-EINVAL); -+ -+ if (unlikely(target->flags & PF_KTHREAD)) -+ /* -+ * Silly kernel, utrace is for users! -+ */ -+ return ERR_PTR(-EPERM); -+ -+ if (!utrace) { -+ if (unlikely(!utrace_task_alloc(target))) -+ return ERR_PTR(-ENOMEM); -+ utrace = task_utrace_struct(target); -+ } -+ -+ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL); -+ if (unlikely(!engine)) -+ return ERR_PTR(-ENOMEM); -+ -+ /* -+ * Initialize the new engine structure. It starts out with one ref -+ * to return. utrace_add_engine() adds another for being attached. -+ */ -+ kref_init(&engine->kref); -+ engine->flags = 0; -+ engine->ops = ops; -+ engine->data = data; -+ engine->release = ops->release; -+ -+ ret = utrace_add_engine(target, utrace, engine, flags, ops, data); -+ -+ if (unlikely(ret)) { -+ kmem_cache_free(utrace_engine_cachep, engine); -+ engine = ERR_PTR(ret); -+ } -+ -+ -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_task); -+ -+/** -+ * utrace_attach_pid - attach new engine, or look up an attached engine -+ * @pid: &struct pid pointer representing thread to attach to -+ * @flags: flag bits combined with OR, see utrace_attach_task() -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * This is the same as utrace_attach_task(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+struct utrace_engine *utrace_attach_pid( -+ struct pid *pid, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine = ERR_PTR(-ESRCH); -+ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); -+ if (task) { -+ engine = utrace_attach_task(task, flags, ops, data); -+ put_task_struct(task); -+ } -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_pid); -+ -+/* -+ * When an engine is detached, the target thread may still see it and -+ * make callbacks until it quiesces. We install a special ops vector -+ * with these two callbacks. When the target thread quiesces, it can -+ * safely free the engine itself. For any event we will always get -+ * the report_quiesce() callback first, so we only need this one -+ * pointer to be set. The only exception is report_reap(), so we -+ * supply that callback too. -+ */ -+static u32 utrace_detached_quiesce(u32 action, struct utrace_engine *engine, -+ unsigned long event) -+{ -+ return UTRACE_DETACH; -+} -+ -+static void utrace_detached_reap(struct utrace_engine *engine, -+ struct task_struct *task) -+{ -+} -+ -+static const struct utrace_engine_ops utrace_detached_ops = { -+ .report_quiesce = &utrace_detached_quiesce, -+ .report_reap = &utrace_detached_reap -+}; -+ -+/* -+ * The caller has to hold a ref on the engine. If the attached flag is -+ * true (all but utrace_barrier() calls), the engine is supposed to be -+ * attached. If the attached flag is false (utrace_barrier() only), -+ * then return -ERESTARTSYS for an engine marked for detach but not yet -+ * fully detached. The task pointer can be invalid if the engine is -+ * detached. -+ * -+ * Get the utrace lock for the target task. -+ * Returns the struct if locked, or ERR_PTR(-errno). -+ * -+ * This has to be robust against races with: -+ * utrace_control(target, UTRACE_DETACH) calls -+ * UTRACE_DETACH after reports -+ * utrace_report_death -+ * utrace_release_task -+ */ -+static struct utrace *get_utrace_lock(struct task_struct *target, -+ struct utrace_engine *engine, -+ bool attached) -+ __acquires(utrace->lock) -+{ -+ struct utrace *utrace; -+ -+ rcu_read_lock(); -+ -+ /* -+ * If this engine was already detached, bail out before we look at -+ * the task_struct pointer at all. If it's detached after this -+ * check, then RCU is still keeping this task_struct pointer valid. -+ * -+ * The ops pointer is NULL when the engine is fully detached. -+ * It's &utrace_detached_ops when it's marked detached but still -+ * on the list. In the latter case, utrace_barrier() still works, -+ * since the target might be in the middle of an old callback. -+ */ -+ if (unlikely(!engine->ops)) { -+ rcu_read_unlock(); -+ return ERR_PTR(-ESRCH); -+ } -+ -+ if (unlikely(engine->ops == &utrace_detached_ops)) { -+ rcu_read_unlock(); -+ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS); -+ } -+ -+ utrace = task_utrace_struct(target); -+ spin_lock(&utrace->lock); -+ if (unlikely(utrace->reap) || unlikely(!engine->ops) || -+ unlikely(engine->ops == &utrace_detached_ops)) { -+ /* -+ * By the time we got the utrace lock, -+ * it had been reaped or detached already. -+ */ -+ spin_unlock(&utrace->lock); -+ utrace = ERR_PTR(-ESRCH); -+ if (!attached && engine->ops == &utrace_detached_ops) -+ utrace = ERR_PTR(-ERESTARTSYS); -+ } -+ rcu_read_unlock(); -+ -+ return utrace; -+} -+ -+/* -+ * Now that we don't hold any locks, run through any -+ * detached engines and free their references. Each -+ * engine had one implicit ref while it was attached. -+ */ -+static void put_detached_list(struct list_head *list) -+{ -+ struct utrace_engine *engine, *next; -+ list_for_each_entry_safe(engine, next, list, entry) { -+ list_del_init(&engine->entry); -+ utrace_engine_put(engine); -+ } -+} -+ -+/* -+ * We use an extra bit in utrace_engine.flags past the event bits, -+ * to record whether the engine is keeping the target thread stopped. -+ * -+ * This bit is set in task_struct.utrace_flags whenever it is set in any -+ * engine's flags. Only utrace_reset() resets it in utrace_flags. -+ */ -+#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) -+ -+static void mark_engine_wants_stop(struct task_struct *task, -+ struct utrace_engine *engine) -+{ -+ engine->flags |= ENGINE_STOP; -+ task->utrace_flags |= ENGINE_STOP; -+} -+ -+static void clear_engine_wants_stop(struct utrace_engine *engine) -+{ -+ engine->flags &= ~ENGINE_STOP; -+} -+ -+static bool engine_wants_stop(struct utrace_engine *engine) -+{ -+ return (engine->flags & ENGINE_STOP) != 0; -+} -+ -+/** -+ * utrace_set_events - choose which event reports a tracing engine gets -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @events: new event mask -+ * -+ * This changes the set of events for which @engine wants callbacks made. -+ * -+ * This fails with -%EALREADY and does nothing if you try to clear -+ * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have -+ * begun, or if you try to newly set %UTRACE_EVENT(%DEATH) or -+ * %UTRACE_EVENT(%QUIESCE) when @target is already dead or dying. -+ * -+ * This fails with -%ESRCH if you try to clear %UTRACE_EVENT(%REAP) when -+ * the @report_reap callback may already have begun, or when @target has -+ * already been detached, including forcible detach on reaping. -+ * -+ * If @target was stopped before the call, then after a successful call, -+ * no event callbacks not requested in @events will be made; if -+ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a -+ * @report_quiesce callback will be made when @target resumes. -+ * -+ * If @target was not stopped and @events excludes some bits that were -+ * set before, this can return -%EINPROGRESS to indicate that @target -+ * may have been making some callback to @engine. When this returns -+ * zero, you can be sure that no event callbacks you've disabled in -+ * @events can be made. If @events only sets new bits that were not set -+ * before on @engine, then -%EINPROGRESS will never be returned. -+ * -+ * To synchronize after an -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * When @target is @current, -%EINPROGRESS is not returned. But note -+ * that a newly-created engine will not receive any callbacks related to -+ * an event notification already in progress. This call enables @events -+ * callbacks to be made as soon as @engine becomes eligible for any -+ * callbacks, see utrace_attach_task(). -+ * -+ * These rules provide for coherent synchronization based on %UTRACE_STOP, -+ * even when %SIGKILL is breaking its normal simple rules. -+ */ -+int utrace_set_events(struct task_struct *target, -+ struct utrace_engine *engine, -+ unsigned long events) -+{ -+ struct utrace *utrace; -+ unsigned long old_flags, old_utrace_flags; -+ int ret = -EALREADY; -+ -+ /* -+ * We just ignore the internal bit, so callers can use -+ * engine->flags to seed bitwise ops for our argument. -+ */ -+ events &= ~ENGINE_STOP; -+ -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); -+ -+ old_utrace_flags = target->utrace_flags; -+ old_flags = engine->flags & ~ENGINE_STOP; -+ -+ /* -+ * If utrace_report_death() is already progress now, -+ * it's too late to clear the death event bits. -+ */ -+ if (((old_flags & ~events) & _UTRACE_DEATH_EVENTS) && utrace->death) -+ goto unlock; -+ -+ /* -+ * When setting these flags, it's essential that we really -+ * synchronize with exit_notify(). They cannot be set after -+ * exit_notify() takes the tasklist_lock. By holding the read -+ * lock here while setting the flags, we ensure that the calls -+ * to tracehook_notify_death() and tracehook_report_death() will -+ * see the new flags. This ensures that utrace_release_task() -+ * knows positively that utrace_report_death() will be called or -+ * that it won't. -+ */ -+ if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) { -+ read_lock(&tasklist_lock); -+ if (unlikely(target->exit_state)) { -+ read_unlock(&tasklist_lock); -+ goto unlock; -+ } -+ target->utrace_flags |= events; -+ read_unlock(&tasklist_lock); -+ } -+ -+ engine->flags = events | (engine->flags & ENGINE_STOP); -+ target->utrace_flags |= events; -+ -+ if ((events & UTRACE_EVENT_SYSCALL) && -+ !(old_utrace_flags & UTRACE_EVENT_SYSCALL)) -+ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE); -+ -+ ret = 0; -+ if ((old_flags & ~events) && target != current && -+ !task_is_stopped_or_traced(target) && !target->exit_state) { -+ /* -+ * This barrier ensures that our engine->flags changes -+ * have hit before we examine utrace->reporting, -+ * pairing with the barrier in start_callback(). If -+ * @target has not yet hit finish_callback() to clear -+ * utrace->reporting, we might be in the middle of a -+ * callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } -+unlock: -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_set_events); -+ -+/* -+ * Asynchronously mark an engine as being detached. -+ * -+ * This must work while the target thread races with us doing -+ * start_callback(), defined below. It uses smp_rmb() between checking -+ * @engine->flags and using @engine->ops. Here we change @engine->ops -+ * first, then use smp_wmb() before changing @engine->flags. This ensures -+ * it can check the old flags before using the old ops, or check the old -+ * flags before using the new ops, or check the new flags before using the -+ * new ops, but can never check the new flags before using the old ops. -+ * Hence, utrace_detached_ops might be used with any old flags in place. -+ * It has report_quiesce() and report_reap() callbacks to handle all cases. -+ */ -+static void mark_engine_detached(struct utrace_engine *engine) -+{ -+ engine->ops = &utrace_detached_ops; -+ smp_wmb(); -+ engine->flags = UTRACE_EVENT(QUIESCE); -+} -+ -+/* -+ * Get @target to stop and return true if it is already stopped now. -+ * If we return false, it will make some event callback soonish. -+ * Called with @utrace locked. -+ */ -+static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) -+{ -+ if (task_is_stopped(target)) { -+ /* -+ * Stopped is considered quiescent; when it wakes up, it will -+ * go through utrace_finish_stop() before doing anything else. -+ */ -+ spin_lock_irq(&target->sighand->siglock); -+ if (likely(task_is_stopped(target))) -+ __set_task_state(target, TASK_TRACED); -+ spin_unlock_irq(&target->sighand->siglock); -+ } else if (utrace->resume > UTRACE_REPORT) { -+ utrace->resume = UTRACE_REPORT; -+ set_notify_resume(target); -+ } -+ -+ return task_is_traced(target); -+} -+ -+/* -+ * If the target is not dead it should not be in tracing -+ * stop any more. Wake it unless it's in job control stop. -+ */ -+static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) -+{ -+ lockdep_assert_held(&utrace->lock); -+ spin_lock_irq(&target->sighand->siglock); -+ if (target->signal->flags & SIGNAL_STOP_STOPPED || -+ target->signal->group_stop_count) -+ target->state = TASK_STOPPED; -+ else -+ wake_up_state(target, __TASK_TRACED); -+ spin_unlock_irq(&target->sighand->siglock); -+} -+ -+/* -+ * This is called when there might be some detached engines on the list or -+ * some stale bits in @task->utrace_flags. Clean them up and recompute the -+ * flags. Returns true if we're now fully detached. -+ * -+ * Called with @utrace->lock held, returns with it released. -+ * After this returns, @utrace might be freed if everything detached. -+ */ -+static bool utrace_reset(struct task_struct *task, struct utrace *utrace) -+ __releases(utrace->lock) -+{ -+ struct utrace_engine *engine, *next; -+ unsigned long flags = 0; -+ LIST_HEAD(detached); -+ -+ splice_attaching(utrace); -+ -+ /* -+ * Update the set of events of interest from the union -+ * of the interests of the remaining tracing engines. -+ * For any engine marked detached, remove it from the list. -+ * We'll collect them on the detached list. -+ */ -+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { -+ if (engine->ops == &utrace_detached_ops) { -+ engine->ops = NULL; -+ list_move(&engine->entry, &detached); -+ } else { -+ flags |= engine->flags | UTRACE_EVENT(REAP); -+ } -+ } -+ -+ if (task->exit_state) { -+ /* -+ * Once it's already dead, we never install any flags -+ * except REAP. When ->exit_state is set and events -+ * like DEATH are not set, then they never can be set. -+ * This ensures that utrace_release_task() knows -+ * positively that utrace_report_death() can never run. -+ */ -+ BUG_ON(utrace->death); -+ flags &= UTRACE_EVENT(REAP); -+ } else if (!(flags & UTRACE_EVENT_SYSCALL) && -+ test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { -+ clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); -+ } -+ -+ if (!flags) { -+ /* -+ * No more engines, cleared out the utrace. -+ */ -+ utrace->resume = UTRACE_RESUME; -+ utrace->signal_handler = 0; -+ } -+ -+ /* -+ * If no more engines want it stopped, wake it up. -+ */ -+ if (task_is_traced(task) && !(flags & ENGINE_STOP)) { -+ /* -+ * It just resumes, so make sure single-step -+ * is not left set. -+ */ -+ if (utrace->resume == UTRACE_RESUME) -+ user_disable_single_step(task); -+ utrace_wakeup(task, utrace); -+ } -+ -+ /* -+ * In theory spin_lock() doesn't imply rcu_read_lock(). -+ * Once we clear ->utrace_flags this task_struct can go away -+ * because tracehook_prepare_release_task() path does not take -+ * utrace->lock when ->utrace_flags == 0. -+ */ -+ rcu_read_lock(); -+ task->utrace_flags = flags; -+ spin_unlock(&utrace->lock); -+ rcu_read_unlock(); -+ -+ put_detached_list(&detached); -+ -+ return !flags; -+} -+ -+void utrace_finish_stop(void) -+{ -+ /* -+ * If we were task_is_traced() and then SIGKILL'ed, make -+ * sure we do nothing until the tracer drops utrace->lock. -+ */ -+ if (unlikely(__fatal_signal_pending(current))) { -+ struct utrace *utrace = task_utrace_struct(current); -+ spin_unlock_wait(&utrace->lock); -+ } -+} -+ -+/* -+ * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. -+ * @task == current, @utrace == current->utrace, which is not locked. -+ * Return true if we were woken up by SIGKILL even though some utrace -+ * engine may still want us to stay stopped. -+ */ -+static void utrace_stop(struct task_struct *task, struct utrace *utrace, -+ enum utrace_resume_action action) -+{ -+relock: -+ spin_lock(&utrace->lock); -+ -+ if (action < utrace->resume) { -+ /* -+ * Ensure a reporting pass when we're resumed. -+ */ -+ utrace->resume = action; -+ if (action == UTRACE_INTERRUPT) -+ set_thread_flag(TIF_SIGPENDING); -+ else -+ set_thread_flag(TIF_NOTIFY_RESUME); -+ } -+ -+ /* -+ * If the ENGINE_STOP bit is clear in utrace_flags, that means -+ * utrace_reset() ran after we processed some UTRACE_STOP return -+ * values from callbacks to get here. If all engines have detached -+ * or resumed us, we don't stop. This check doesn't require -+ * siglock, but it should follow the interrupt/report bookkeeping -+ * steps (this can matter for UTRACE_RESUME but not UTRACE_DETACH). -+ */ -+ if (unlikely(!(task->utrace_flags & ENGINE_STOP))) { -+ utrace_reset(task, utrace); -+ if (task->utrace_flags & ENGINE_STOP) -+ goto relock; -+ return; -+ } -+ -+ /* -+ * The siglock protects us against signals. As well as SIGKILL -+ * waking us up, we must synchronize with the signal bookkeeping -+ * for stop signals and SIGCONT. -+ */ -+ spin_lock_irq(&task->sighand->siglock); -+ -+ if (unlikely(__fatal_signal_pending(task))) { -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); -+ return; -+ } -+ -+ __set_current_state(TASK_TRACED); -+ -+ /* -+ * If there is a group stop in progress, -+ * we must participate in the bookkeeping. -+ */ -+ if (unlikely(task->signal->group_stop_count) && -+ !--task->signal->group_stop_count) -+ task->signal->flags = SIGNAL_STOP_STOPPED; -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); -+ -+ schedule(); -+ -+ utrace_finish_stop(); -+ -+ /* -+ * While in TASK_TRACED, we were considered "frozen enough". -+ * Now that we woke up, it's crucial if we're supposed to be -+ * frozen that we freeze now before running anything substantial. -+ */ -+ try_to_freeze(); -+ -+ /* -+ * While we were in TASK_TRACED, complete_signal() considered -+ * us "uninterested" in signal wakeups. Now make sure our -+ * TIF_SIGPENDING state is correct for normal running. -+ */ -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+} -+ -+/* -+ * Called by release_task() with @reap set to true. -+ * Called by utrace_report_death() with @reap set to false. -+ * On reap, make report_reap callbacks and clean out @utrace -+ * unless still making callbacks. On death, update bookkeeping -+ * and handle the reap work if release_task() came in first. -+ */ -+void utrace_maybe_reap(struct task_struct *target, struct utrace *utrace, -+ bool reap) -+{ -+ struct utrace_engine *engine, *next; -+ struct list_head attached; -+ -+ spin_lock(&utrace->lock); -+ -+ if (reap) { -+ /* -+ * If the target will do some final callbacks but hasn't -+ * finished them yet, we know because it clears these event -+ * bits after it's done. Instead of cleaning up here and -+ * requiring utrace_report_death() to cope with it, we -+ * delay the REAP report and the teardown until after the -+ * target finishes its death reports. -+ */ -+ utrace->reap = 1; -+ -+ if (target->utrace_flags & _UTRACE_DEATH_EVENTS) { -+ spin_unlock(&utrace->lock); -+ return; -+ } -+ } else { -+ /* -+ * After we unlock with this flag clear, any competing -+ * utrace_control/utrace_set_events calls know that we've -+ * finished our callbacks and any detach bookkeeping. -+ */ -+ utrace->death = 0; -+ -+ if (!utrace->reap) { -+ /* -+ * We're just dead, not reaped yet. This will -+ * reset @target->utrace_flags so the later call -+ * with @reap set won't hit the check above. -+ */ -+ utrace_reset(target, utrace); -+ return; -+ } -+ } -+ -+ /* -+ * utrace_add_engine() checks ->utrace_flags != 0. Since -+ * @utrace->reap is set, nobody can set or clear UTRACE_EVENT(REAP) -+ * in @engine->flags or change @engine->ops and nobody can change -+ * @utrace->attached after we drop the lock. -+ */ -+ target->utrace_flags = 0; -+ -+ /* -+ * We clear out @utrace->attached before we drop the lock so -+ * that find_matching_engine() can't come across any old engine -+ * while we are busy tearing it down. -+ */ -+ list_replace_init(&utrace->attached, &attached); -+ list_splice_tail_init(&utrace->attaching, &attached); -+ -+ spin_unlock(&utrace->lock); -+ -+ list_for_each_entry_safe(engine, next, &attached, entry) { -+ if (engine->flags & UTRACE_EVENT(REAP)) -+ engine->ops->report_reap(engine, target); -+ -+ engine->ops = NULL; -+ engine->flags = 0; -+ list_del_init(&engine->entry); -+ -+ utrace_engine_put(engine); -+ } -+} -+ -+/* -+ * You can't do anything to a dead task but detach it. -+ * If release_task() has been called, you can't do that. -+ * -+ * On the exit path, DEATH and QUIESCE event bits are set only -+ * before utrace_report_death() has taken the lock. At that point, -+ * the death report will come soon, so disallow detach until it's -+ * done. This prevents us from racing with it detaching itself. -+ * -+ * Called only when @target->exit_state is nonzero. -+ */ -+static inline int utrace_control_dead(struct task_struct *target, -+ struct utrace *utrace, -+ enum utrace_resume_action action) -+{ -+ lockdep_assert_held(&utrace->lock); -+ -+ if (action != UTRACE_DETACH || unlikely(utrace->reap)) -+ return -ESRCH; -+ -+ if (unlikely(utrace->death)) -+ /* -+ * We have already started the death report. We can't -+ * prevent the report_death and report_reap callbacks, -+ * so tell the caller they will happen. -+ */ -+ return -EALREADY; -+ -+ return 0; -+} -+ -+/** -+ * utrace_control - control a thread being traced by a tracing engine -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @action: &enum utrace_resume_action for thread to do -+ * -+ * This is how a tracing engine asks a traced thread to do something. -+ * This call is controlled by the @action argument, which has the -+ * same meaning as the &enum utrace_resume_action value returned by -+ * event reporting callbacks. -+ * -+ * If @target is already dead (@target->exit_state nonzero), -+ * all actions except %UTRACE_DETACH fail with -%ESRCH. -+ * -+ * The following sections describe each option for the @action argument. -+ * -+ * UTRACE_DETACH: -+ * -+ * After this, the @engine data structure is no longer accessible, -+ * and the thread might be reaped. The thread will start running -+ * again if it was stopped and no longer has any attached engines -+ * that want it stopped. -+ * -+ * If the @report_reap callback may already have begun, this fails -+ * with -%ESRCH. If the @report_death callback may already have -+ * begun, this fails with -%EALREADY. -+ * -+ * If @target is not already stopped, then a callback to this engine -+ * might be in progress or about to start on another CPU. If so, -+ * then this returns -%EINPROGRESS; the detach happens as soon as -+ * the pending callback is finished. To synchronize after an -+ * -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * If @target is properly stopped before utrace_control() is called, -+ * then after successful return it's guaranteed that no more callbacks -+ * to the @engine->ops vector will be made. -+ * -+ * The only exception is %SIGKILL (and exec or group-exit by another -+ * thread in the group), which can cause asynchronous @report_death -+ * and/or @report_reap callbacks even when %UTRACE_STOP was used. -+ * (In that event, this fails with -%ESRCH or -%EALREADY, see above.) -+ * -+ * UTRACE_STOP: -+ * -+ * This asks that @target stop running. This returns 0 only if -+ * @target is already stopped, either for tracing or for job -+ * control. Then @target will remain stopped until another -+ * utrace_control() call is made on @engine; @target can be woken -+ * only by %SIGKILL (or equivalent, such as exec or termination by -+ * another thread in the same thread group). -+ * -+ * This returns -%EINPROGRESS if @target is not already stopped. -+ * Then the effect is like %UTRACE_REPORT. A @report_quiesce or -+ * @report_signal callback will be made soon. Your callback can -+ * then return %UTRACE_STOP to keep @target stopped. -+ * -+ * This does not interrupt system calls in progress, including ones -+ * that sleep for a long time. For that, use %UTRACE_INTERRUPT. -+ * To interrupt system calls and then keep @target stopped, your -+ * @report_signal callback can return %UTRACE_STOP. -+ * -+ * UTRACE_RESUME: -+ * -+ * Just let @target continue running normally, reversing the effect -+ * of a previous %UTRACE_STOP. If another engine is keeping @target -+ * stopped, then it remains stopped until all engines let it resume. -+ * If @target was not stopped, this has no effect. -+ * -+ * UTRACE_REPORT: -+ * -+ * This is like %UTRACE_RESUME, but also ensures that there will be -+ * a @report_quiesce or @report_signal callback made soon. If -+ * @target had been stopped, then there will be a callback before it -+ * resumes running normally. If another engine is keeping @target -+ * stopped, then there might be no callbacks until all engines let -+ * it resume. -+ * -+ * Since this is meaningless unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_INTERRUPT: -+ * -+ * This is like %UTRACE_REPORT, but ensures that @target will make a -+ * @report_signal callback before it resumes or delivers signals. -+ * If @target was in a system call or about to enter one, work in -+ * progress will be interrupted as if by %SIGSTOP. If another -+ * engine is keeping @target stopped, then there might be no -+ * callbacks until all engines let it resume. -+ * -+ * This gives @engine an opportunity to introduce a forced signal -+ * disposition via its @report_signal callback. -+ * -+ * UTRACE_SINGLESTEP: -+ * -+ * It's invalid to use this unless arch_has_single_step() returned true. -+ * This is like %UTRACE_RESUME, but resumes for one user instruction only. -+ * -+ * Note that passing %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP to -+ * utrace_control() or returning it from an event callback alone does -+ * not necessarily ensure that stepping will be enabled. If there are -+ * more callbacks made to any engine before returning to user mode, -+ * then the resume action is chosen only by the last set of callbacks. -+ * To be sure, enable %UTRACE_EVENT(%QUIESCE) and look for the -+ * @report_quiesce callback with a zero event mask, or the -+ * @report_signal callback with %UTRACE_SIGNAL_REPORT. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_BLOCKSTEP: -+ * -+ * It's invalid to use this unless arch_has_block_step() returned true. -+ * This is like %UTRACE_SINGLESTEP, but resumes for one whole basic -+ * block of user instructions. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * %UTRACE_BLOCKSTEP devolves to %UTRACE_SINGLESTEP when another -+ * tracing engine is using %UTRACE_SINGLESTEP at the same time. -+ */ -+int utrace_control(struct task_struct *target, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ struct utrace *utrace; -+ bool reset; -+ int ret; -+ -+ if (unlikely(action >= UTRACE_RESUME_MAX)) { -+ WARN(1, "invalid action argument to utrace_control()!"); -+ return -EINVAL; -+ } -+ -+ /* -+ * This is a sanity check for a programming error in the caller. -+ * Their request can only work properly in all cases by relying on -+ * a follow-up callback, but they didn't set one up! This check -+ * doesn't do locking, but it shouldn't matter. The caller has to -+ * be synchronously sure the callback is set up to be operating the -+ * interface properly. -+ */ -+ if (action >= UTRACE_REPORT && action < UTRACE_RESUME && -+ unlikely(!(engine->flags & UTRACE_EVENT(QUIESCE)))) { -+ WARN(1, "utrace_control() with no QUIESCE callback in place!"); -+ return -EINVAL; -+ } -+ -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); -+ -+ reset = task_is_traced(target); -+ ret = 0; -+ -+ /* -+ * ->exit_state can change under us, this doesn't matter. -+ * We do not care about ->exit_state in fact, but we do -+ * care about ->reap and ->death. If either flag is set, -+ * we must also see ->exit_state != 0. -+ */ -+ if (unlikely(target->exit_state)) { -+ ret = utrace_control_dead(target, utrace, action); -+ if (ret) { -+ spin_unlock(&utrace->lock); -+ return ret; -+ } -+ reset = true; -+ } -+ -+ switch (action) { -+ case UTRACE_STOP: -+ mark_engine_wants_stop(target, engine); -+ if (!reset && !utrace_do_stop(target, utrace)) -+ ret = -EINPROGRESS; -+ reset = false; -+ break; -+ -+ case UTRACE_DETACH: -+ if (engine_wants_stop(engine)) -+ target->utrace_flags &= ~ENGINE_STOP; -+ mark_engine_detached(engine); -+ reset = reset || utrace_do_stop(target, utrace); -+ if (!reset) { -+ /* -+ * As in utrace_set_events(), this barrier ensures -+ * that our engine->flags changes have hit before we -+ * examine utrace->reporting, pairing with the barrier -+ * in start_callback(). If @target has not yet hit -+ * finish_callback() to clear utrace->reporting, we -+ * might be in the middle of a callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } -+ break; -+ -+ case UTRACE_RESUME: -+ clear_engine_wants_stop(engine); -+ break; -+ -+ case UTRACE_BLOCKSTEP: -+ /* -+ * Resume from stopped, step one block. -+ * We fall through to treat it like UTRACE_SINGLESTEP. -+ */ -+ if (unlikely(!arch_has_block_step())) { -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); -+ action = UTRACE_SINGLESTEP; -+ } -+ -+ case UTRACE_SINGLESTEP: -+ /* -+ * Resume from stopped, step one instruction. -+ * We fall through to the UTRACE_REPORT case. -+ */ -+ if (unlikely(!arch_has_single_step())) { -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ reset = false; -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ case UTRACE_REPORT: -+ /* -+ * Make the thread call tracehook_notify_resume() soon. -+ * But don't bother if it's already been interrupted. -+ * In that case, utrace_get_signal() will be reporting soon. -+ */ -+ clear_engine_wants_stop(engine); -+ if (action < utrace->resume) { -+ utrace->resume = action; -+ set_notify_resume(target); -+ } -+ break; -+ -+ case UTRACE_INTERRUPT: -+ /* -+ * Make the thread call tracehook_get_signal() soon. -+ */ -+ clear_engine_wants_stop(engine); -+ if (utrace->resume == UTRACE_INTERRUPT) -+ break; -+ utrace->resume = UTRACE_INTERRUPT; -+ -+ /* -+ * If it's not already stopped, interrupt it now. We need -+ * the siglock here in case it calls recalc_sigpending() -+ * and clears its own TIF_SIGPENDING. By taking the lock, -+ * we've serialized any later recalc_sigpending() after our -+ * setting of utrace->resume to force it on. -+ */ -+ if (reset) { -+ /* -+ * This is really just to keep the invariant that -+ * TIF_SIGPENDING is set with UTRACE_INTERRUPT. -+ * When it's stopped, we know it's always going -+ * through utrace_get_signal() and will recalculate. -+ */ -+ set_tsk_thread_flag(target, TIF_SIGPENDING); -+ } else { -+ struct sighand_struct *sighand; -+ unsigned long irqflags; -+ sighand = lock_task_sighand(target, &irqflags); -+ if (likely(sighand)) { -+ signal_wake_up(target, 0); -+ unlock_task_sighand(target, &irqflags); -+ } -+ } -+ break; -+ -+ default: -+ BUG(); /* We checked it on entry. */ -+ } -+ -+ /* -+ * Let the thread resume running. If it's not stopped now, -+ * there is nothing more we need to do. -+ */ -+ if (reset) -+ utrace_reset(target, utrace); -+ else -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_control); -+ -+/** -+ * utrace_barrier - synchronize with simultaneous tracing callbacks -+ * @target: thread to affect -+ * @engine: engine to affect (can be detached) -+ * -+ * This blocks while @target might be in the midst of making a callback to -+ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS. -+ * A return value of zero means no callback from @target to @engine was -+ * in progress. Any effect of its return value (such as %UTRACE_STOP) has -+ * already been applied to @engine. -+ * -+ * It's not necessary to keep the @target pointer alive for this call. -+ * It's only necessary to hold a ref on @engine. This will return -+ * safely even if @target has been reaped and has no task refs. -+ * -+ * A successful return from utrace_barrier() guarantees its ordering -+ * with respect to utrace_set_events() and utrace_control() calls. If -+ * @target was not properly stopped, event callbacks just disabled might -+ * still be in progress; utrace_barrier() waits until there is no chance -+ * an unwanted callback can be in progress. -+ */ -+int utrace_barrier(struct task_struct *target, struct utrace_engine *engine) -+{ -+ struct utrace *utrace; -+ int ret = -ERESTARTSYS; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ do { -+ utrace = get_utrace_lock(target, engine, false); -+ if (unlikely(IS_ERR(utrace))) { -+ ret = PTR_ERR(utrace); -+ if (ret != -ERESTARTSYS) -+ break; -+ } else { -+ /* -+ * All engine state changes are done while -+ * holding the lock, i.e. before we get here. -+ * Since we have the lock, we only need to -+ * worry about @target making a callback. -+ * When it has entered start_callback() but -+ * not yet gotten to finish_callback(), we -+ * will see utrace->reporting == @engine. -+ * When @target doesn't take the lock, it uses -+ * barriers to order setting utrace->reporting -+ * before it examines the engine state. -+ */ -+ if (utrace->reporting != engine) -+ ret = 0; -+ spin_unlock(&utrace->lock); -+ if (!ret) -+ break; -+ } -+ schedule_timeout_interruptible(1); -+ } while (!signal_pending(current)); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_barrier); -+ -+/* -+ * This is local state used for reporting loops, perhaps optimized away. -+ */ -+struct utrace_report { -+ u32 result; -+ enum utrace_resume_action action; -+ enum utrace_resume_action resume_action; -+ bool detaches; -+ bool spurious; -+}; -+ -+#define INIT_REPORT(var) \ -+ struct utrace_report var = { \ -+ .action = UTRACE_RESUME, \ -+ .resume_action = UTRACE_RESUME, \ -+ .spurious = true \ -+ } -+ -+/* -+ * We are now making the report, so clear the flag saying we need one. -+ * When there is a new attach, ->pending_attach is set just so we will -+ * know to do splice_attaching() here before the callback loop. -+ */ -+static enum utrace_resume_action start_report(struct utrace *utrace) -+{ -+ enum utrace_resume_action resume = utrace->resume; -+ if (utrace->pending_attach || -+ (resume > UTRACE_INTERRUPT && resume < UTRACE_RESUME)) { -+ spin_lock(&utrace->lock); -+ splice_attaching(utrace); -+ resume = utrace->resume; -+ if (resume > UTRACE_INTERRUPT) -+ utrace->resume = UTRACE_RESUME; -+ spin_unlock(&utrace->lock); -+ } -+ return resume; -+} -+ -+static inline void finish_report_reset(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) -+{ -+ if (unlikely(report->spurious || report->detaches)) { -+ spin_lock(&utrace->lock); -+ if (utrace_reset(task, utrace)) -+ report->action = UTRACE_RESUME; -+ } -+} -+ -+/* -+ * Complete a normal reporting pass, pairing with a start_report() call. -+ * This handles any UTRACE_DETACH or UTRACE_REPORT or UTRACE_INTERRUPT -+ * returns from engine callbacks. If @will_not_stop is true and any -+ * engine's last callback used UTRACE_STOP, we do UTRACE_REPORT here to -+ * ensure we stop before user mode. If there were no callbacks made, it -+ * will recompute @task->utrace_flags to avoid another false-positive. -+ */ -+static void finish_report(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, bool will_not_stop) -+{ -+ enum utrace_resume_action resume = report->action; -+ -+ if (resume == UTRACE_STOP) -+ resume = will_not_stop ? UTRACE_REPORT : UTRACE_RESUME; -+ -+ if (resume < utrace->resume) { -+ spin_lock(&utrace->lock); -+ utrace->resume = resume; -+ if (resume == UTRACE_INTERRUPT) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ else -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ spin_unlock(&utrace->lock); -+ } -+ -+ finish_report_reset(task, utrace, report); -+} -+ -+static void finish_callback_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ if (action == UTRACE_DETACH) { -+ /* -+ * By holding the lock here, we make sure that -+ * utrace_barrier() (really get_utrace_lock()) sees the -+ * effect of this detach. Otherwise utrace_barrier() could -+ * return 0 after this callback had returned UTRACE_DETACH. -+ * This way, a 0 return is an unambiguous indicator that any -+ * callback returning UTRACE_DETACH has indeed caused detach. -+ */ -+ spin_lock(&utrace->lock); -+ engine->ops = &utrace_detached_ops; -+ spin_unlock(&utrace->lock); -+ } -+ -+ /* -+ * If utrace_control() was used, treat that like UTRACE_DETACH here. -+ */ -+ if (engine->ops == &utrace_detached_ops) { -+ report->detaches = true; -+ return; -+ } -+ -+ if (action < report->action) -+ report->action = action; -+ -+ if (action != UTRACE_STOP) { -+ if (action < report->resume_action) -+ report->resume_action = action; -+ -+ if (engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ clear_engine_wants_stop(engine); -+ spin_unlock(&utrace->lock); -+ } -+ -+ return; -+ } -+ -+ if (!engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ /* -+ * If utrace_control() came in and detached us -+ * before we got the lock, we must not stop now. -+ */ -+ if (unlikely(engine->ops == &utrace_detached_ops)) -+ report->detaches = true; -+ else -+ mark_engine_wants_stop(task, engine); -+ spin_unlock(&utrace->lock); -+ } -+} -+ -+/* -+ * Apply the return value of one engine callback to @report. -+ * Returns true if @engine detached and should not get any more callbacks. -+ */ -+static bool finish_callback(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ u32 ret) -+{ -+ report->result = ret & ~UTRACE_RESUME_MASK; -+ finish_callback_report(task, utrace, report, engine, -+ utrace_resume_action(ret)); -+ -+ /* -+ * Now that we have applied the effect of the return value, -+ * clear this so that utrace_barrier() can stop waiting. -+ * A subsequent utrace_control() can stop or resume @engine -+ * and know this was ordered after its callback's action. -+ * -+ * We don't need any barriers here because utrace_barrier() -+ * takes utrace->lock. If we touched engine->flags above, -+ * the lock guaranteed this change was before utrace_barrier() -+ * examined utrace->reporting. -+ */ -+ utrace->reporting = NULL; -+ -+ /* -+ * We've just done an engine callback. These are allowed to sleep, -+ * though all well-behaved ones restrict that to blocking kalloc() -+ * or quickly-acquired mutex_lock() and the like. This is a good -+ * place to make sure tracing engines don't introduce too much -+ * latency under voluntary preemption. -+ */ -+ might_sleep(); -+ -+ return engine->ops == &utrace_detached_ops; -+} -+ -+/* -+ * Start the callbacks for @engine to consider @event (a bit mask). -+ * This makes the report_quiesce() callback first. If @engine wants -+ * a specific callback for @event, we return the ops vector to use. -+ * If not, we return NULL. The return value from the ops->callback -+ * function called should be passed to finish_callback(). -+ */ -+static const struct utrace_engine_ops *start_callback( -+ struct utrace *utrace, struct utrace_report *report, -+ struct utrace_engine *engine, struct task_struct *task, -+ unsigned long event) -+{ -+ const struct utrace_engine_ops *ops; -+ unsigned long want; -+ -+ /* -+ * This barrier ensures that we've set utrace->reporting before -+ * we examine engine->flags or engine->ops. utrace_barrier() -+ * relies on this ordering to indicate that the effect of any -+ * utrace_control() and utrace_set_events() calls is in place -+ * by the time utrace->reporting can be seen to be NULL. -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ -+ /* -+ * This pairs with the barrier in mark_engine_detached(). -+ * It makes sure that we never see the old ops vector with -+ * the new flags, in case the original vector had no report_quiesce. -+ */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; -+ -+ if ((want & UTRACE_EVENT(QUIESCE)) || ops == &utrace_detached_ops) { -+ if (finish_callback(task, utrace, report, engine, -+ (*ops->report_quiesce)(report->action, -+ engine, event))) -+ return NULL; -+ -+ if (!event) { -+ /* We only got here to report QUIESCE */ -+ report->spurious = false; -+ return NULL; -+ } -+ -+ /* -+ * finish_callback() reset utrace->reporting after the -+ * quiesce callback. Now we set it again (as above) -+ * before re-examining engine->flags, which could have -+ * been changed synchronously by ->report_quiesce or -+ * asynchronously by utrace_control() or utrace_set_events(). -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ want = engine->flags; -+ } -+ -+ if (want & ENGINE_STOP) -+ report->action = UTRACE_STOP; -+ -+ if (want & event) { -+ report->spurious = false; -+ return ops; -+ } -+ -+ utrace->reporting = NULL; -+ return NULL; -+} -+ -+/* -+ * Do a normal reporting pass for engines interested in @event. -+ * @callback is the name of the member in the ops vector, and remaining -+ * args are the extras it takes after the standard three args. -+ */ -+#define REPORT_CALLBACKS(rev, task, utrace, report, event, callback, ...) \ -+ do { \ -+ struct utrace_engine *engine; \ -+ const struct utrace_engine_ops *ops; \ -+ list_for_each_entry##rev(engine, &utrace->attached, entry) { \ -+ ops = start_callback(utrace, report, engine, task, \ -+ event); \ -+ if (!ops) \ -+ continue; \ -+ finish_callback(task, utrace, report, engine, \ -+ (*ops->callback)(__VA_ARGS__)); \ -+ } \ -+ } while (0) -+#define REPORT(task, utrace, report, event, callback, ...) \ -+ do { \ -+ start_report(utrace); \ -+ REPORT_CALLBACKS(, task, utrace, report, event, callback, \ -+ (report)->action, engine, ## __VA_ARGS__); \ -+ finish_report(task, utrace, report, true); \ -+ } while (0) -+ -+/* -+ * Called iff UTRACE_EVENT(EXEC) flag is set. -+ */ -+void utrace_report_exec(struct linux_binfmt *fmt, struct linux_binprm *bprm, -+ struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXEC), -+ report_exec, fmt, bprm, regs); -+} -+ -+static u32 do_report_syscall_entry(struct pt_regs *regs, -+ struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ u32 resume_report) -+{ -+ start_report(utrace); -+ REPORT_CALLBACKS(_reverse, task, utrace, report, -+ UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry, -+ resume_report | report->result | report->action, -+ engine, regs); -+ finish_report(task, utrace, report, false); -+ -+ if (report->action != UTRACE_STOP) -+ return 0; -+ -+ utrace_stop(task, utrace, report->resume_action); -+ -+ if (fatal_signal_pending(task)) { -+ /* -+ * We are continuing despite UTRACE_STOP because of a -+ * SIGKILL. Don't let the system call actually proceed. -+ */ -+ report->result = UTRACE_SYSCALL_ABORT; -+ } else if (utrace->resume <= UTRACE_REPORT) { -+ /* -+ * If we've been asked for another report after our stop, -+ * go back to report (and maybe stop) again before we run -+ * the system call. The second (and later) reports are -+ * marked with the UTRACE_SYSCALL_RESUMED flag so that -+ * engines know this is a second report at the same -+ * entry. This gives them the chance to examine the -+ * registers anew after they might have been changed -+ * while we were stopped. -+ */ -+ report->detaches = false; -+ report->spurious = true; -+ report->action = report->resume_action = UTRACE_RESUME; -+ return UTRACE_SYSCALL_RESUMED; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Called iff UTRACE_EVENT(SYSCALL_ENTRY) flag is set. -+ * Return true to prevent the system call. -+ */ -+bool utrace_report_syscall_entry(struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ u32 resume_report = 0; -+ -+ do { -+ resume_report = do_report_syscall_entry(regs, task, utrace, -+ &report, resume_report); -+ } while (resume_report); -+ -+ return utrace_syscall_action(report.result) == UTRACE_SYSCALL_ABORT; -+} -+ -+/* -+ * Called iff UTRACE_EVENT(SYSCALL_EXIT) flag is set. -+ */ -+void utrace_report_syscall_exit(struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(SYSCALL_EXIT), -+ report_syscall_exit, regs); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(CLONE) flag is set. -+ * This notification call blocks the wake_up_new_task call on the child. -+ * So we must not quiesce here. tracehook_report_clone_complete will do -+ * a quiescence check momentarily. -+ */ -+void utrace_report_clone(unsigned long clone_flags, struct task_struct *child) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ /* -+ * We don't use the REPORT() macro here, because we need -+ * to clear utrace->cloning before finish_report(). -+ * After finish_report(), utrace can be a stale pointer -+ * in cases when report.action is still UTRACE_RESUME. -+ */ -+ start_report(utrace); -+ utrace->cloning = child; -+ -+ REPORT_CALLBACKS(, task, utrace, &report, -+ UTRACE_EVENT(CLONE), report_clone, -+ report.action, engine, clone_flags, child); -+ -+ utrace->cloning = NULL; -+ finish_report(task, utrace, &report, !(clone_flags & CLONE_VFORK)); -+ -+ /* -+ * For a vfork, we will go into an uninterruptible block waiting -+ * for the child. We need UTRACE_STOP to happen before this, not -+ * after. For CLONE_VFORK, utrace_finish_vfork() will be called. -+ */ -+ if (report.action == UTRACE_STOP && (clone_flags & CLONE_VFORK)) { -+ spin_lock(&utrace->lock); -+ utrace->vfork_stop = 1; -+ spin_unlock(&utrace->lock); -+ } -+} -+ -+/* -+ * We're called after utrace_report_clone() for a CLONE_VFORK. -+ * If UTRACE_STOP was left from the clone report, we stop here. -+ * After this, we'll enter the uninterruptible wait_for_completion() -+ * waiting for the child. -+ */ -+void utrace_finish_vfork(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace->vfork_stop) { -+ spin_lock(&utrace->lock); -+ utrace->vfork_stop = 0; -+ spin_unlock(&utrace->lock); -+ utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ -+ } -+} -+ -+/* -+ * Called iff UTRACE_EVENT(JCTL) flag is set. -+ * -+ * Called with siglock held. -+ */ -+void utrace_report_jctl(int notify, int what) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(JCTL), -+ report_jctl, what, notify); -+ -+ spin_lock_irq(&task->sighand->siglock); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(EXIT) flag is set. -+ */ -+void utrace_report_exit(long *exit_code) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ long orig_code = *exit_code; -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXIT), -+ report_exit, orig_code, exit_code); -+ -+ if (report.action == UTRACE_STOP) -+ utrace_stop(task, utrace, report.resume_action); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(DEATH) or UTRACE_EVENT(QUIESCE) flag is set. -+ * -+ * It is always possible that we are racing with utrace_release_task here. -+ * For this reason, utrace_release_task checks for the event bits that get -+ * us here, and delays its cleanup for us to do. -+ */ -+void utrace_report_death(struct task_struct *task, struct utrace *utrace, -+ bool group_dead, int signal) -+{ -+ INIT_REPORT(report); -+ -+ BUG_ON(!task->exit_state); -+ -+ /* -+ * We are presently considered "quiescent"--which is accurate -+ * inasmuch as we won't run any more user instructions ever again. -+ * But for utrace_control and utrace_set_events to be robust, they -+ * must be sure whether or not we will run any more callbacks. If -+ * a call comes in before we do, taking the lock here synchronizes -+ * us so we don't run any callbacks just disabled. Calls that come -+ * in while we're running the callbacks will see the exit.death -+ * flag and know that we are not yet fully quiescent for purposes -+ * of detach bookkeeping. -+ */ -+ spin_lock(&utrace->lock); -+ BUG_ON(utrace->death); -+ utrace->death = 1; -+ utrace->resume = UTRACE_RESUME; -+ splice_attaching(utrace); -+ spin_unlock(&utrace->lock); -+ -+ REPORT_CALLBACKS(, task, utrace, &report, UTRACE_EVENT(DEATH), -+ report_death, engine, group_dead, signal); -+ -+ utrace_maybe_reap(task, utrace, false); -+} -+ -+/* -+ * Finish the last reporting pass before returning to user mode. -+ */ -+static void finish_resume_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) -+{ -+ finish_report_reset(task, utrace, report); -+ -+ switch (report->action) { -+ case UTRACE_STOP: -+ utrace_stop(task, utrace, report->resume_action); -+ break; -+ -+ case UTRACE_INTERRUPT: -+ if (!signal_pending(task)) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ break; -+ -+ case UTRACE_BLOCKSTEP: -+ if (likely(arch_has_block_step())) { -+ user_enable_block_step(task); -+ break; -+ } -+ -+ /* -+ * This means some callback is to blame for failing -+ * to check arch_has_block_step() itself. Warn and -+ * then fall through to treat it as SINGLESTEP. -+ */ -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); -+ -+ case UTRACE_SINGLESTEP: -+ if (likely(arch_has_single_step())) { -+ user_enable_single_step(task); -+ } else { -+ /* -+ * This means some callback is to blame for failing -+ * to check arch_has_single_step() itself. Spew -+ * about it so the loser will fix his module. -+ */ -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ } -+ break; -+ -+ case UTRACE_REPORT: -+ case UTRACE_RESUME: -+ default: -+ user_disable_single_step(task); -+ break; -+ } -+} -+ -+/* -+ * This is called when TIF_NOTIFY_RESUME had been set (and is now clear). -+ * We are close to user mode, and this is the place to report or stop. -+ * When we return, we're going to user mode or into the signals code. -+ */ -+void utrace_resume(struct task_struct *task, struct pt_regs *regs) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ struct utrace_engine *engine; -+ -+ /* -+ * Some machines get here with interrupts disabled. The same arch -+ * code path leads to calling into get_signal_to_deliver(), which -+ * implicitly reenables them by virtue of spin_unlock_irq. -+ */ -+ local_irq_enable(); -+ -+ /* -+ * If this flag is still set it's because there was a signal -+ * handler setup done but no report_signal following it. Clear -+ * the flag before we get to user so it doesn't confuse us later. -+ */ -+ if (unlikely(utrace->signal_handler)) { -+ spin_lock(&utrace->lock); -+ utrace->signal_handler = 0; -+ spin_unlock(&utrace->lock); -+ } -+ -+ /* -+ * Update our bookkeeping even if there are no callbacks made here. -+ */ -+ report.action = start_report(utrace); -+ -+ switch (report.action) { -+ case UTRACE_RESUME: -+ /* -+ * Anything we might have done was already handled by -+ * utrace_get_signal(), or this is an entirely spurious -+ * call. (The arch might use TIF_NOTIFY_RESUME for other -+ * purposes as well as calling us.) -+ */ -+ return; -+ case UTRACE_REPORT: -+ if (unlikely(!(task->utrace_flags & UTRACE_EVENT(QUIESCE)))) -+ break; -+ /* -+ * Do a simple reporting pass, with no specific -+ * callback after report_quiesce. -+ */ -+ report.action = UTRACE_RESUME; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ start_callback(utrace, &report, engine, task, 0); -+ break; -+ default: -+ /* -+ * Even if this report was truly spurious, there is no need -+ * for utrace_reset() now. TIF_NOTIFY_RESUME was already -+ * cleared--it doesn't stay spuriously set. -+ */ -+ report.spurious = false; -+ break; -+ } -+ -+ /* -+ * Finish the report and either stop or get ready to resume. -+ * If utrace->resume was not UTRACE_REPORT, this applies its -+ * effect now (i.e. step or interrupt). -+ */ -+ finish_resume_report(task, utrace, &report); -+} -+ -+/* -+ * Return true if current has forced signal_pending(). -+ * -+ * This is called only when current->utrace_flags is nonzero, so we know -+ * that current->utrace must be set. It's not inlined in tracehook.h -+ * just so that struct utrace can stay opaque outside this file. -+ */ -+bool utrace_interrupt_pending(void) -+{ -+ return task_utrace_struct(current)->resume == UTRACE_INTERRUPT; -+} -+ -+/* -+ * Take the siglock and push @info back on our queue. -+ * Returns with @task->sighand->siglock held. -+ */ -+static void push_back_signal(struct task_struct *task, siginfo_t *info) -+ __acquires(task->sighand->siglock) -+{ -+ struct sigqueue *q; -+ -+ if (unlikely(!info->si_signo)) { /* Oh, a wise guy! */ -+ spin_lock_irq(&task->sighand->siglock); -+ return; -+ } -+ -+ q = sigqueue_alloc(); -+ if (likely(q)) { -+ q->flags = 0; -+ copy_siginfo(&q->info, info); -+ } -+ -+ spin_lock_irq(&task->sighand->siglock); -+ -+ sigaddset(&task->pending.signal, info->si_signo); -+ if (likely(q)) -+ list_add(&q->list, &task->pending.list); -+ -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+} -+ -+/* -+ * This is the hook from the signals code, called with the siglock held. -+ * Here is the ideal place to stop. We also dequeue and intercept signals. -+ */ -+int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, -+ siginfo_t *info, struct k_sigaction *return_ka) -+ __releases(task->sighand->siglock) -+ __acquires(task->sighand->siglock) -+{ -+ struct utrace *utrace; -+ struct k_sigaction *ka; -+ INIT_REPORT(report); -+ struct utrace_engine *engine; -+ const struct utrace_engine_ops *ops; -+ unsigned long event, want; -+ u32 ret; -+ int signr; -+ -+ utrace = task_utrace_struct(task); -+ if (utrace->resume < UTRACE_RESUME || -+ utrace->pending_attach || utrace->signal_handler) { -+ enum utrace_resume_action resume; -+ -+ /* -+ * We've been asked for an explicit report before we -+ * even check for pending signals. -+ */ -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ -+ spin_lock(&utrace->lock); -+ -+ splice_attaching(utrace); -+ -+ report.result = utrace->signal_handler ? -+ UTRACE_SIGNAL_HANDLER : UTRACE_SIGNAL_REPORT; -+ utrace->signal_handler = 0; -+ -+ resume = utrace->resume; -+ utrace->resume = UTRACE_RESUME; -+ -+ spin_unlock(&utrace->lock); -+ -+ /* -+ * Make sure signal_pending() only returns true -+ * if there are real signals pending. -+ */ -+ if (signal_pending(task)) { -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ if (resume > UTRACE_REPORT) { -+ /* -+ * We only got here to process utrace->resume. -+ * Despite no callbacks, this report is not spurious. -+ */ -+ report.action = resume; -+ report.spurious = false; -+ finish_resume_report(task, utrace, &report); -+ return -1; -+ } else if (!(task->utrace_flags & UTRACE_EVENT(QUIESCE))) { -+ /* -+ * We only got here to clear utrace->signal_handler. -+ */ -+ return -1; -+ } -+ -+ /* -+ * Do a reporting pass for no signal, just for EVENT(QUIESCE). -+ * The engine callbacks can fill in *info and *return_ka. -+ * We'll pass NULL for the @orig_ka argument to indicate -+ * that there was no original signal. -+ */ -+ event = 0; -+ ka = NULL; -+ memset(return_ka, 0, sizeof *return_ka); -+ } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -+ unlikely(task->signal->group_stop_count)) { -+ /* -+ * If no engine is interested in intercepting signals or -+ * we must stop, let the caller just dequeue them normally -+ * or participate in group-stop. -+ */ -+ return 0; -+ } else { -+ /* -+ * Steal the next signal so we can let tracing engines -+ * examine it. From the signal number and sigaction, -+ * determine what normal delivery would do. If no -+ * engine perturbs it, we'll do that by returning the -+ * signal number after setting *return_ka. -+ */ -+ signr = dequeue_signal(task, &task->blocked, info); -+ if (signr == 0) -+ return signr; -+ BUG_ON(signr != info->si_signo); -+ -+ ka = &task->sighand->action[signr - 1]; -+ *return_ka = *ka; -+ -+ /* -+ * We are never allowed to interfere with SIGKILL. -+ * Just punt after filling in *return_ka for our caller. -+ */ -+ if (signr == SIGKILL) -+ return signr; -+ -+ if (ka->sa.sa_handler == SIG_IGN) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (ka->sa.sa_handler != SIG_DFL) { -+ event = UTRACE_EVENT(SIGNAL); -+ report.result = UTRACE_SIGNAL_DELIVER; -+ } else if (sig_kernel_coredump(signr)) { -+ event = UTRACE_EVENT(SIGNAL_CORE); -+ report.result = UTRACE_SIGNAL_CORE; -+ } else if (sig_kernel_ignore(signr)) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (signr == SIGSTOP) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_STOP; -+ } else if (sig_kernel_stop(signr)) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_TSTP; -+ } else { -+ event = UTRACE_EVENT(SIGNAL_TERM); -+ report.result = UTRACE_SIGNAL_TERM; -+ } -+ -+ /* -+ * Now that we know what event type this signal is, we -+ * can short-circuit if no engines care about those. -+ */ -+ if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0) -+ return signr; -+ -+ /* -+ * We have some interested engines, so tell them about -+ * the signal and let them change its disposition. -+ */ -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ /* -+ * This reporting pass chooses what signal disposition we'll act on. -+ */ -+ list_for_each_entry(engine, &utrace->attached, entry) { -+ /* -+ * See start_callback() comment about this barrier. -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ -+ /* -+ * This pairs with the barrier in mark_engine_detached(), -+ * see start_callback() comments. -+ */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; -+ -+ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { -+ utrace->reporting = NULL; -+ continue; -+ } -+ -+ if (ops->report_signal) -+ ret = (*ops->report_signal)( -+ report.result | report.action, engine, -+ regs, info, ka, return_ka); -+ else -+ ret = (report.result | (*ops->report_quiesce)( -+ report.action, engine, event)); -+ -+ /* -+ * Avoid a tight loop reporting again and again if some -+ * engine is too stupid. -+ */ -+ switch (utrace_resume_action(ret)) { -+ default: -+ break; -+ case UTRACE_INTERRUPT: -+ case UTRACE_REPORT: -+ ret = (ret & ~UTRACE_RESUME_MASK) | UTRACE_RESUME; -+ break; -+ } -+ -+ finish_callback(task, utrace, &report, engine, ret); -+ } -+ -+ /* -+ * We express the chosen action to the signals code in terms -+ * of a representative signal whose default action does it. -+ * Our caller uses our return value (signr) to decide what to -+ * do, but uses info->si_signo as the signal number to report. -+ */ -+ switch (utrace_signal_action(report.result)) { -+ case UTRACE_SIGNAL_TERM: -+ signr = SIGTERM; -+ break; -+ -+ case UTRACE_SIGNAL_CORE: -+ signr = SIGQUIT; -+ break; -+ -+ case UTRACE_SIGNAL_STOP: -+ signr = SIGSTOP; -+ break; -+ -+ case UTRACE_SIGNAL_TSTP: -+ signr = SIGTSTP; -+ break; -+ -+ case UTRACE_SIGNAL_DELIVER: -+ signr = info->si_signo; -+ -+ if (return_ka->sa.sa_handler == SIG_DFL) { -+ /* -+ * We'll do signr's normal default action. -+ * For ignore, we'll fall through below. -+ * For stop/death, break locks and returns it. -+ */ -+ if (likely(signr) && !sig_kernel_ignore(signr)) -+ break; -+ } else if (return_ka->sa.sa_handler != SIG_IGN && -+ likely(signr)) { -+ /* -+ * Complete the bookkeeping after the report. -+ * The handler will run. If an engine wanted to -+ * stop or step, then make sure we do another -+ * report after signal handler setup. -+ */ -+ if (report.action != UTRACE_RESUME) -+ report.action = UTRACE_INTERRUPT; -+ finish_report(task, utrace, &report, true); -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ /* -+ * We do the SA_ONESHOT work here since the -+ * normal path will only touch *return_ka now. -+ */ -+ if (unlikely(return_ka->sa.sa_flags & SA_ONESHOT)) { -+ return_ka->sa.sa_flags &= ~SA_ONESHOT; -+ if (likely(valid_signal(signr))) { -+ ka = &task->sighand->action[signr - 1]; -+ ka->sa.sa_handler = SIG_DFL; -+ } -+ } -+ -+ return signr; -+ } -+ -+ /* Fall through for an ignored signal. */ -+ -+ case UTRACE_SIGNAL_IGN: -+ case UTRACE_SIGNAL_REPORT: -+ default: -+ /* -+ * If the signal is being ignored, then we are on the way -+ * directly back to user mode. We can stop here, or step, -+ * as in utrace_resume(), above. After we've dealt with that, -+ * our caller will relock and come back through here. -+ */ -+ finish_resume_report(task, utrace, &report); -+ -+ if (unlikely(fatal_signal_pending(task))) { -+ /* -+ * The only reason we woke up now was because of a -+ * SIGKILL. Don't do normal dequeuing in case it -+ * might get a signal other than SIGKILL. That would -+ * perturb the death state so it might differ from -+ * what the debugger would have allowed to happen. -+ * Instead, pluck out just the SIGKILL to be sure -+ * we'll die immediately with nothing else different -+ * from the quiescent state the debugger wanted us in. -+ */ -+ sigset_t sigkill_only; -+ siginitsetinv(&sigkill_only, sigmask(SIGKILL)); -+ spin_lock_irq(&task->sighand->siglock); -+ signr = dequeue_signal(task, &sigkill_only, info); -+ BUG_ON(signr != SIGKILL); -+ *return_ka = task->sighand->action[SIGKILL - 1]; -+ return signr; -+ } -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) { -+ push_back_signal(task, info); -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ return -1; -+ } -+ -+ /* -+ * Complete the bookkeeping after the report. -+ * This sets utrace->resume if UTRACE_STOP was used. -+ */ -+ finish_report(task, utrace, &report, true); -+ -+ return_ka->sa.sa_handler = SIG_DFL; -+ -+ /* -+ * If this signal is fatal, si_signo gets through as exit_code. -+ * We can't allow a completely bogus value there or else core -+ * kernel code can freak out. (If an engine wants to control -+ * the exit_code value exactly, it can do so in report_exit.) -+ * We'll produce a big complaint in dmesg, but won't crash. -+ * That's nicer for debugging your utrace engine. -+ */ -+ if (unlikely(info->si_signo & 0x80)) { -+ WARN(1, "utrace engine left bogus si_signo value!"); -+ info->si_signo = SIGTRAP; -+ } -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ if (sig_kernel_stop(signr)) -+ task->group_stop |= GROUP_STOP_DEQUEUED; -+ -+ return signr; -+} -+ -+/* -+ * This gets called after a signal handler has been set up. -+ * We set a flag so the next report knows it happened. -+ * If we're already stepping, make sure we do a report_signal. -+ * If not, make sure we get into utrace_resume() where we can -+ * clear the signal_handler flag before resuming. -+ */ -+void utrace_signal_handler(struct task_struct *task, int stepping) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ spin_lock(&utrace->lock); -+ -+ utrace->signal_handler = 1; -+ if (utrace->resume > UTRACE_INTERRUPT) { -+ if (stepping) { -+ utrace->resume = UTRACE_INTERRUPT; -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ } else if (utrace->resume == UTRACE_RESUME) { -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ } -+ } -+ -+ spin_unlock(&utrace->lock); -+} -+ -+/** -+ * utrace_prepare_examine - prepare to examine thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: temporary state, a &struct utrace_examiner pointer -+ * -+ * This call prepares to safely examine the thread @target using -+ * &struct user_regset calls, or direct access to thread-synchronous fields. -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, it must be held stopped via %UTRACE_STOP by @engine. -+ * -+ * This call may block the caller until @target stays stopped, so it must -+ * be called only after the caller is sure @target is about to unschedule. -+ * This means a zero return from a utrace_control() call on @engine giving -+ * %UTRACE_STOP, or a report_quiesce() or report_signal() callback to -+ * @engine that used %UTRACE_STOP in its return value. -+ * -+ * Returns -%ESRCH if @target is dead or -%EINVAL if %UTRACE_STOP was -+ * not used. If @target has started running again despite %UTRACE_STOP -+ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN. -+ * -+ * When this call returns zero, it's safe to use &struct user_regset -+ * calls and task_user_regset_view() on @target and to examine some of -+ * its fields directly. When the examination is complete, a -+ * utrace_finish_examine() call must follow to check whether it was -+ * completed safely. -+ */ -+int utrace_prepare_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) -+{ -+ int ret = 0; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->exit_state)) -+ ret = -ESRCH; -+ else { -+ exam->state = target->state; -+ if (unlikely(exam->state == TASK_RUNNING)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ } -+ rcu_read_unlock(); -+ -+ if (likely(!ret)) { -+ exam->ncsw = wait_task_inactive(target, exam->state); -+ put_task_struct(target); -+ if (unlikely(!exam->ncsw)) -+ ret = -EAGAIN; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_prepare_examine); -+ -+/** -+ * utrace_finish_examine - complete an examination of thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: pointer passed to utrace_prepare_examine() call -+ * -+ * This call completes an examination on the thread @target begun by a -+ * paired utrace_prepare_examine() call with the same arguments that -+ * returned success (zero). -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, this returns zero if @target has remained unscheduled -+ * since the paired utrace_prepare_examine() call returned zero. -+ * -+ * When this returns an error, any examination done since the paired -+ * utrace_prepare_examine() call is unreliable and the data extracted -+ * should be discarded. The error is -%EINVAL if @engine is not -+ * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly. -+ */ -+int utrace_finish_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) -+{ -+ int ret = 0; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->state != exam->state)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ rcu_read_unlock(); -+ -+ if (likely(!ret)) { -+ unsigned long ncsw = wait_task_inactive(target, exam->state); -+ if (unlikely(ncsw != exam->ncsw)) -+ ret = -EAGAIN; -+ put_task_struct(target); -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_finish_examine); -+ -+/* -+ * This is declared in linux/regset.h and defined in machine-dependent -+ * code. We put the export here to ensure no machine forgets it. -+ */ -+EXPORT_SYMBOL_GPL(task_user_regset_view); -+ -+/* -+ * Called with rcu_read_lock() held. -+ */ -+void task_utrace_proc_status(struct seq_file *m, struct task_struct *p) -+{ -+ seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); -+} --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:04 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:04 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:03 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2259ED812A; - Thu, 30 Jun 2011 20:23:03 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id Ex9fFDzwy1Zb; Thu, 30 Jun 2011 20:23:03 -0400 (EDT) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 0EF28D810F; - Thu, 30 Jun 2011 20:23:03 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610Mt6X021086; - Thu, 30 Jun 2011 20:22:56 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:03 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:01 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 02/19] utrace: remove jobctl bits -Message-ID: <20110701002101.GA25779@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 1890 -Lines: 56 - -- change utrace_get_signal() to check GROUP_STOP_PENDING instead of - signal->group_stop_count. With the recent changes group_stop_count - doesn't necessarily mean this task should participate in group stop. - -- remove the "participate in group stop" code from utrace_wakeup() and - utrace_stop(), this is no longer needed and wrong. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 16 ++-------------- - 1 files changed, 2 insertions(+), 14 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index f332d65..6e7fafb 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -648,11 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- if (target->signal->flags & SIGNAL_STOP_STOPPED || -- target->signal->group_stop_count) -- target->state = TASK_STOPPED; -- else -- wake_up_state(target, __TASK_TRACED); -+ wake_up_state(target, __TASK_TRACED); - spin_unlock_irq(&target->sighand->siglock); - } - -@@ -805,14 +801,6 @@ relock: - - __set_current_state(TASK_TRACED); - -- /* -- * If there is a group stop in progress, -- * we must participate in the bookkeeping. -- */ -- if (unlikely(task->signal->group_stop_count) && -- !--task->signal->group_stop_count) -- task->signal->flags = SIGNAL_STOP_STOPPED; -- - spin_unlock_irq(&task->sighand->siglock); - spin_unlock(&utrace->lock); - -@@ -2036,7 +2024,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, - ka = NULL; - memset(return_ka, 0, sizeof *return_ka); - } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -- unlikely(task->signal->group_stop_count)) { -+ unlikely(task->group_stop & GROUP_STOP_PENDING)) { - /* - * If no engine is interested in intercepting signals or - * we must stop, let the caller just dequeue them normally --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:05 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:05 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:06 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6B38AD812A; - Thu, 30 Jun 2011 20:23:06 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id f4153Z6E7KGl; Thu, 30 Jun 2011 20:23:06 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 55D4AD810F; - Thu, 30 Jun 2011 20:23:06 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610Mwi2015168; - Thu, 30 Jun 2011 20:22:59 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:06 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:04 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 03/19] ptrace: take ->siglock around s/TRACED/RUNNING/ -Message-ID: <20110701002104.GA25787@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 1624 -Lines: 56 - -change ptrace_resume() and ptrace_stop() to take ->siglock around changing -task->state from TRACED to RUNNING. - -With this patch __TASK_TRACED/STOPPED bits are fully protected by ->siglock, -nobody can set or clear these bits without ->siglock held. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 8 +++++++- - kernel/signal.c | 3 +++ - 2 files changed, 10 insertions(+), 1 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 2df1157..9988b13 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -534,6 +534,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) - static int ptrace_resume(struct task_struct *child, long request, - unsigned long data) - { -+ unsigned long flags; -+ - if (!valid_signal(data)) - return -EIO; - -@@ -562,7 +564,11 @@ static int ptrace_resume(struct task_struct *child, long request, - } - - child->exit_code = data; -- wake_up_state(child, __TASK_TRACED); -+ -+ if (lock_task_sighand(child, &flags)) { -+ wake_up_state(child, __TASK_TRACED); -+ unlock_task_sighand(child, &flags); -+ } - - return 0; - } -diff --git a/kernel/signal.c b/kernel/signal.c -index ff76786..2138cee 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1799,7 +1799,10 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - if (gstop_done) - do_notify_parent_cldstop(current, false, why); - -+ spin_lock_irq(¤t->sighand->siglock); - __set_current_state(TASK_RUNNING); -+ spin_unlock_irq(¤t->sighand->siglock); -+ - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:06 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:06 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:09 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E1AB7D812A; - Thu, 30 Jun 2011 20:23:09 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id QhOnA49nS3Vp; Thu, 30 Jun 2011 20:23:09 -0400 (EDT) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C5E15D810F; - Thu, 30 Jun 2011 20:23:09 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610N2Kd007635; - Thu, 30 Jun 2011 20:23:02 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:10 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:07 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 04/19] introduce wake_up_quiescent() -Message-ID: <20110701002107.GA25790@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 3104 -Lines: 93 - -No functional changes. Add the new helper, wake_up_quiescent(task, state), -which simply returns wake_up_state(task, state). Change all callers which -do wake_up_state(STOPPED/TRACED) to use the new helper. ptrace_stop() is -a bit special, it does __set_current_state(RUNNING) in the very unlikely -case, change it as well. - -Signed-off-by: Oleg Nesterov ---- - include/linux/signal.h | 2 ++ - kernel/ptrace.c | 2 +- - kernel/signal.c | 12 ++++++++++-- - kernel/utrace.c | 2 +- - 4 files changed, 14 insertions(+), 4 deletions(-) - -diff --git a/include/linux/signal.h b/include/linux/signal.h -index a822300..2be3712 100644 ---- a/include/linux/signal.h -+++ b/include/linux/signal.h -@@ -239,6 +239,8 @@ static inline int valid_signal(unsigned long sig) - struct timespec; - struct pt_regs; - -+extern int wake_up_quiescent(struct task_struct *p, unsigned int state); -+ - extern int next_signal(struct sigpending *pending, sigset_t *mask); - extern int do_send_sig_info(int sig, struct siginfo *info, - struct task_struct *p, bool group); -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 9988b13..26ae214 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -566,7 +566,7 @@ static int ptrace_resume(struct task_struct *child, long request, - child->exit_code = data; - - if (lock_task_sighand(child, &flags)) { -- wake_up_state(child, __TASK_TRACED); -+ wake_up_quiescent(child, __TASK_TRACED); - unlock_task_sighand(child, &flags); - } - -diff --git a/kernel/signal.c b/kernel/signal.c -index 2138cee..4fcf1c7 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -652,6 +652,14 @@ void signal_wake_up(struct task_struct *t, int resume) - } - - /* -+ * wakes up the STOPPED/TRACED task, must be called with ->siglock held. -+ */ -+int wake_up_quiescent(struct task_struct *p, unsigned int state) -+{ -+ return wake_up_state(p, state); -+} -+ -+/* - * Remove signals in mask from the pending set and queue. - * Returns 1 if any signals were found. - * -@@ -811,7 +819,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) - do { - task_clear_group_stop_pending(t); - rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); -- wake_up_state(t, __TASK_STOPPED); -+ wake_up_quiescent(t, __TASK_STOPPED); - } while_each_thread(p, t); - - /* -@@ -1800,7 +1808,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - do_notify_parent_cldstop(current, false, why); - - spin_lock_irq(¤t->sighand->siglock); -- __set_current_state(TASK_RUNNING); -+ wake_up_quiescent(current, __TASK_TRACED); - spin_unlock_irq(¤t->sighand->siglock); - - if (clear_code) -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 6e7fafb..d7c547c 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -648,7 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- wake_up_state(target, __TASK_TRACED); -+ wake_up_quiescent(target, __TASK_TRACED); - spin_unlock_irq(&target->sighand->siglock); - } - --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:07 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:07 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:13 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2CF811287F3; - Thu, 30 Jun 2011 20:23:13 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id dNPA3WxO-7pp; Thu, 30 Jun 2011 20:23:13 -0400 (EDT) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 154D61287DD; - Thu, 30 Jun 2011 20:23:13 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610N5nY021107; - Thu, 30 Jun 2011 20:23:06 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:13 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:11 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 05/19] introduce ptrace_signal_wake_up() -Message-ID: <20110701002111.GA25797@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 1975 -Lines: 68 - -Add the new helper, ptrace_signal_wake_up(), change ptrace.c to use -it instead of signal_wake_up(). - -The new helper does almost the same, except: - - - it doesn't use the TASK_WAKEKILL bit to wake up the TRACED - or STOPPED task, it uses __TASK_STOPPED | __TASK_TRACED - explicitly. This is what ptrace actually wants, it should - never wake up a TASK_KILLABLE task. - - This should be cleanuped upatream, signal_wake_up() should - take the state as an argument, not a boolean. Until then - we add a new static helper. - - - it uses wake_up_quiescent() instead of wake_up_state(). - -Thereafter every change from STOPPED/TRACED to RUNNING is done via -wake_up_quiescent(). - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 16 ++++++++++++++-- - 1 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 26ae214..0b2aba5 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -24,6 +24,18 @@ - #include - #include - -+static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) -+{ -+ unsigned int state; -+ -+ set_tsk_thread_flag(p, TIF_SIGPENDING); -+ -+ state = TASK_INTERRUPTIBLE; -+ if (quiescent) -+ state |= (__TASK_STOPPED | __TASK_TRACED); -+ if (!wake_up_quiescent(p, state)) -+ kick_process(p); -+} - - /* - * ptrace a task: make the debugger its new parent and -@@ -92,7 +104,7 @@ void __ptrace_unlink(struct task_struct *child) - * TASK_KILLABLE sleeps. - */ - if (child->group_stop & GROUP_STOP_PENDING || task_is_traced(child)) -- signal_wake_up(child, task_is_traced(child)); -+ ptrace_signal_wake_up(child, task_is_traced(child)); - - spin_unlock(&child->sighand->siglock); - } -@@ -245,7 +257,7 @@ static int ptrace_attach(struct task_struct *task) - */ - if (task_is_stopped(task)) { - task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING; -- signal_wake_up(task, 1); -+ ptrace_signal_wake_up(task, 1); - wait_trap = true; - } - --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:08 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:08 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:16 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6FB379C0CB; - Thu, 30 Jun 2011 20:23:16 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id IYB64KKErOyI; Thu, 30 Jun 2011 20:23:16 -0400 (EDT) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 597119C0C5; - Thu, 30 Jun 2011 20:23:16 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610N8bE032569; - Thu, 30 Jun 2011 20:23:09 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:16 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:14 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 06/19] wait_task_inactive: treat task->state and - match_state as bitmasks -Message-ID: <20110701002114.GA25804@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 1558 -Lines: 39 - -Change wait_task_inactive() to check "state & match_state" instead of -"state == match_state". This should not make any difference, but this -allows us to add more "stopped" bits which can be set or cleared -independently. - -IOW. wait_task_inactive() assumes that if task->state != 0, it can -only be changed to TASK_RUNNING. Currently this is true, and in this -case "state & match_state" continues to work. But, unlike the current -check, it also works if task->state has other bits set while the caller -is only interested in, say, __TASK_TRACED. - -Note: I think wait_task_inactive() should be cleanuped upstrean anyway, -nowadays we have TASK_WAKING and task->state != 0 doesn't necessarily -mean it is TASK_RUNNING. It also makes sense to exclude the !TASK_REPORT -bits during the check. Finally, probably this patch makes sense anyway -even without utrace. For example, a stopped _and_ traced thread could -have task->state = TASK_STOPPED | TASK_TRACED, this can be useful. - -Signed-off-by: Oleg Nesterov ---- - kernel/sched.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/kernel/sched.c b/kernel/sched.c -index 3f2e502..ade7997 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -2277,7 +2277,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) - * is actually now running somewhere else! - */ - while (task_running(rq, p)) { -- if (match_state && unlikely(p->state != match_state)) -+ if (match_state && !likely(p->state & match_state)) - return 0; - cpu_relax(); - } --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:09 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:09 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:19 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A6BD4D810F; - Thu, 30 Jun 2011 20:23:19 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 2ovLSk6W1SGg; Thu, 30 Jun 2011 20:23:19 -0400 (EDT) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8DBABD812A; - Thu, 30 Jun 2011 20:23:19 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610NCUq026299; - Thu, 30 Jun 2011 20:23:12 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:19 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:17 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 07/19] introduce TASK_UTRACED state -Message-ID: <20110701002117.GA25807@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 2913 -Lines: 84 - -Introduce TASK_UTRACED state, will be used by utrace instead of TASK_TRACED. - -Note: this state is reported as "t (tracing stop)" to the user-space to -avoid the confusion. IOW, it looks like TASK_TRACED in /proc/pid/status. - -Signed-off-by: Oleg Nesterov ---- - fs/proc/array.c | 11 ++++++----- - include/linux/sched.h | 20 +++++++++++--------- - 2 files changed, 17 insertions(+), 14 deletions(-) - -diff --git a/fs/proc/array.c b/fs/proc/array.c -index 496fef3..bfaa998 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -138,11 +138,12 @@ static const char * const task_state_array[] = { - "D (disk sleep)", /* 2 */ - "T (stopped)", /* 4 */ - "t (tracing stop)", /* 8 */ -- "Z (zombie)", /* 16 */ -- "X (dead)", /* 32 */ -- "x (dead)", /* 64 */ -- "K (wakekill)", /* 128 */ -- "W (waking)", /* 256 */ -+ "t (tracing stop)", /* 16 (stopped by utrace) */ -+ "Z (zombie)", /* 32 */ -+ "X (dead)", /* 64 */ -+ "x (dead)", /* 128 */ -+ "K (wakekill)", /* 256 */ -+ "W (waking)", /* 512 */ - }; - - static inline const char *get_task_state(struct task_struct *tsk) -diff --git a/include/linux/sched.h b/include/linux/sched.h -index b87de83..7a0008c 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -184,16 +184,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) - #define TASK_UNINTERRUPTIBLE 2 - #define __TASK_STOPPED 4 - #define __TASK_TRACED 8 -+#define __TASK_UTRACED 16 - /* in tsk->exit_state */ --#define EXIT_ZOMBIE 16 --#define EXIT_DEAD 32 -+#define EXIT_ZOMBIE 32 -+#define EXIT_DEAD 64 - /* in tsk->state again */ --#define TASK_DEAD 64 --#define TASK_WAKEKILL 128 --#define TASK_WAKING 256 --#define TASK_STATE_MAX 512 -+#define TASK_DEAD 128 -+#define TASK_WAKEKILL 256 -+#define TASK_WAKING 512 -+#define TASK_STATE_MAX 1024 - --#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW" -+#define TASK_STATE_TO_CHAR_STR "RSDTtUZXxKW" - - extern char ___assert_task_state[1 - 2*!!( - sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; -@@ -202,15 +203,16 @@ extern char ___assert_task_state[1 - 2*!!( - #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) - #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) - #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) -+#define TASK_UTRACED (TASK_WAKEKILL | __TASK_UTRACED) - - /* Convenience macros for the sake of wake_up */ - #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) --#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) -+#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) - - /* get_task_state() */ - #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ - TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ -- __TASK_TRACED) -+ __TASK_TRACED | __TASK_UTRACED) - - #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) - #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:10 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:10 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:23 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1A66AD812A; - Thu, 30 Jun 2011 20:23:23 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id fctUcQ+-lYpk; Thu, 30 Jun 2011 20:23:23 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F2D35D810F; - Thu, 30 Jun 2011 20:23:22 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NF1u015200; - Thu, 30 Jun 2011 20:23:15 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:23 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:20 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 08/19] utrace: use TASK_UTRACED instead of TASK_TRACED -Message-ID: <20110701002120.GA25814@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 4316 -Lines: 130 - -Change utrace.c to use TASK_UTRACED instead of TASK_TRACED. - -- utrace_stop/utrace_wakeup: simply use the new state - -- utrace_do_stop: do not clear STOPPED/TRACED, but add the new - __TASK_UTRACED bit to state the fact that both ptrace and utrace - want this task to be stopped - -- naturally, do not use task_is_traced() to check if this task was - stopped by utrace, use the new task_is_utraced() helper which - checks __TASK_UTRACED. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 26 ++++++++++++++------------ - 1 files changed, 14 insertions(+), 12 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index d7c547c..be98607 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -462,6 +462,8 @@ static void put_detached_list(struct list_head *list) - */ - #define ENGINE_STOP (1UL << _UTRACE_NEVENTS) - -+#define task_is_utraced(task) ((task->state & __TASK_UTRACED) != 0) -+ - static void mark_engine_wants_stop(struct task_struct *task, - struct utrace_engine *engine) - { -@@ -576,7 +578,7 @@ int utrace_set_events(struct task_struct *target, - - ret = 0; - if ((old_flags & ~events) && target != current && -- !task_is_stopped_or_traced(target) && !target->exit_state) { -+ !task_is_utraced(target) && !target->exit_state) { - /* - * This barrier ensures that our engine->flags changes - * have hit before we examine utrace->reporting, -@@ -623,21 +625,21 @@ static void mark_engine_detached(struct utrace_engine *engine) - */ - static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) - { -- if (task_is_stopped(target)) { -+ if (task_is_stopped_or_traced(target)) { - /* - * Stopped is considered quiescent; when it wakes up, it will - * go through utrace_finish_stop() before doing anything else. - */ - spin_lock_irq(&target->sighand->siglock); -- if (likely(task_is_stopped(target))) -- __set_task_state(target, TASK_TRACED); -+ if (likely(task_is_stopped_or_traced(target))) -+ target->state |= TASK_UTRACED; - spin_unlock_irq(&target->sighand->siglock); - } else if (utrace->resume > UTRACE_REPORT) { - utrace->resume = UTRACE_REPORT; - set_notify_resume(target); - } - -- return task_is_traced(target); -+ return task_is_utraced(target); - } - - /* -@@ -648,7 +650,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- wake_up_quiescent(target, __TASK_TRACED); -+ wake_up_quiescent(target, __TASK_UTRACED); - spin_unlock_irq(&target->sighand->siglock); - } - -@@ -710,7 +712,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - /* - * If no more engines want it stopped, wake it up. - */ -- if (task_is_traced(task) && !(flags & ENGINE_STOP)) { -+ if (task_is_utraced(task) && !(flags & ENGINE_STOP)) { - /* - * It just resumes, so make sure single-step - * is not left set. -@@ -749,7 +751,7 @@ void utrace_finish_stop(void) - } - - /* -- * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. -+ * Perform %UTRACE_STOP, i.e. block in TASK_UTRACED until woken up. - * @task == current, @utrace == current->utrace, which is not locked. - * Return true if we were woken up by SIGKILL even though some utrace - * engine may still want us to stay stopped. -@@ -799,7 +801,7 @@ relock: - return; - } - -- __set_current_state(TASK_TRACED); -+ __set_current_state(TASK_UTRACED); - - spin_unlock_irq(&task->sighand->siglock); - spin_unlock(&utrace->lock); -@@ -809,14 +811,14 @@ relock: - utrace_finish_stop(); - - /* -- * While in TASK_TRACED, we were considered "frozen enough". -+ * While in TASK_UTRACED, we were considered "frozen enough". - * Now that we woke up, it's crucial if we're supposed to be - * frozen that we freeze now before running anything substantial. - */ - try_to_freeze(); - - /* -- * While we were in TASK_TRACED, complete_signal() considered -+ * While we were in TASK_UTRACED, complete_signal() considered - * us "uninterested" in signal wakeups. Now make sure our - * TIF_SIGPENDING state is correct for normal running. - */ -@@ -1087,7 +1089,7 @@ int utrace_control(struct task_struct *target, - if (unlikely(IS_ERR(utrace))) - return PTR_ERR(utrace); - -- reset = task_is_traced(target); -+ reset = task_is_utraced(target); - ret = 0; - - /* --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:12 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:12 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:26 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 289969C0C5; - Thu, 30 Jun 2011 20:23:26 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id q99JSaVz2X1O; Thu, 30 Jun 2011 20:23:26 -0400 (EDT) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 143F89C0C3; - Thu, 30 Jun 2011 20:23:26 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610NI9T021133; - Thu, 30 Jun 2011 20:23:19 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:26 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:24 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 09/19] tracehooks: kill tracehook_finish_jctl(), add - tracehook_finish_stop() -Message-ID: <20110701002124.GA25817@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 2782 -Lines: 86 - -tracehook_finish_jctl() is needed to avoid the races with SIGKILL -which wakes up UTRACED task, and thus it should be called every time -after the STOPPED/TRACED/UTRACED returns from schedule(), remember -that TASK_UTRACED can be added while the task is STOPPED/UTRACED. - -- rename it to tracehook_finish_stop(),jctl no longer matches the - reality. - -- change do_signal_state() to call this helper right after schedule(), - otherwise this logic is broken by the upstream changes - -- now that utrace doesn't control TASK_TRACED bit, ptrace_stop() must - call this helper too. - -Signed-off-by: Oleg Nesterov ---- - include/linux/tracehook.h | 6 +++--- - kernel/signal.c | 5 +++-- - kernel/utrace.c | 2 +- - 3 files changed, 7 insertions(+), 6 deletions(-) - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 7d7bdde..3c7b6b3 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -528,11 +528,11 @@ static inline int tracehook_get_signal(struct task_struct *task, - } - - /** -- * tracehook_finish_jctl - report about return from job control stop -+ * tracehook_finish_stop - report about return from STOPPED/TRACED - * -- * This is called by do_signal_stop() after wakeup. -+ * This is called by do_signal_stop() and ptrace_stop after wakeup. - */ --static inline void tracehook_finish_jctl(void) -+static inline void tracehook_finish_stop(void) - { - if (task_utrace_flags(current)) - utrace_finish_stop(); -diff --git a/kernel/signal.c b/kernel/signal.c -index 4fcf1c7..a7979ad 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1816,6 +1816,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - read_unlock(&tasklist_lock); - } - -+ tracehook_finish_stop(); - /* - * While in TASK_TRACED, we were considered "frozen enough". - * Now that we woke up, it's crucial if we're supposed to be -@@ -1952,6 +1953,8 @@ retry: - /* Now we don't run again until woken by SIGCONT or SIGKILL */ - schedule(); - -+ tracehook_finish_stop(); -+ - spin_lock_irq(¤t->sighand->siglock); - } else { - ptrace_stop(current->group_stop & GROUP_STOP_SIGMASK, -@@ -1974,8 +1977,6 @@ retry: - - spin_unlock_irq(¤t->sighand->siglock); - -- tracehook_finish_jctl(); -- - return 1; - } - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index be98607..daa96b9 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -741,7 +741,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - void utrace_finish_stop(void) - { - /* -- * If we were task_is_traced() and then SIGKILL'ed, make -+ * If we were task_is_utraced() and then SIGKILL'ed, make - * sure we do nothing until the tracer drops utrace->lock. - */ - if (unlikely(__fatal_signal_pending(current))) { --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:13 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:13 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:29 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A748FD813B; - Thu, 30 Jun 2011 20:23:29 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id EwbxGxAU7ASi; Thu, 30 Jun 2011 20:23:29 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 72761D810F; - Thu, 30 Jun 2011 20:23:29 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NMAW015213; - Thu, 30 Jun 2011 20:23:22 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:29 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:27 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 10/19] teach wake_up_quiescent() to do "selective" wake_up -Message-ID: <20110701002127.GA25824@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 1335 -Lines: 46 - -Both utrace and ptrace can want the same thread to be quiescent, in this -case its state is TASK_TRACED | TASK_UTRACED. And this also means that -this task must not run unless both utrace and ptrace resume it. - -Change wake_up_quiescent(p, state) to do "p->state &= ~state" and return -false unless there is no more "quiescent" bits in task->state. - -Signed-off-by: Oleg Nesterov ---- - kernel/signal.c | 15 +++++++++++++++ - 1 files changed, 15 insertions(+), 0 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index a7979ad..57552e6 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -651,11 +651,26 @@ void signal_wake_up(struct task_struct *t, int resume) - kick_process(t); - } - -+#define STATE_QUIESCENT (__TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) - /* - * wakes up the STOPPED/TRACED task, must be called with ->siglock held. - */ - int wake_up_quiescent(struct task_struct *p, unsigned int state) - { -+ unsigned int quiescent = (p->state & STATE_QUIESCENT); -+ -+ WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE)); -+ -+ if (quiescent) { -+ state &= ~TASK_INTERRUPTIBLE; -+ if ((quiescent & ~state) != 0) { -+ p->state &= ~state; -+ WARN_ON(!(p->state & STATE_QUIESCENT)); -+ WARN_ON(!(p->state & TASK_WAKEKILL)); -+ return 0; -+ } -+ } -+ - return wake_up_state(p, state); - } - --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:14 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:14 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:32 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C94CF9C0C5; - Thu, 30 Jun 2011 20:23:32 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 9R-z4gQXQITf; Thu, 30 Jun 2011 20:23:32 -0400 (EDT) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B55759C0C3; - Thu, 30 Jun 2011 20:23:32 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610NPe5021144; - Thu, 30 Jun 2011 20:23:25 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:33 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:30 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 11/19] ptrace_stop: do not assume the task is running after - wake_up_quiescent() -Message-ID: <20110701002130.GA25827@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 962 -Lines: 31 - -If ptrace_stop() sets TASK_TRACED and then detects we should not stop, -it can race with utrace_do_stop() which can see TASK_TRACED and add -TASK_UTRACED. In this case we should stop for utrace needs. - -Signed-off-by: Oleg Nesterov ---- - kernel/signal.c | 8 ++++++++ - 1 files changed, 8 insertions(+), 0 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index 57552e6..89e691d 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1829,6 +1829,14 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); -+ -+ /* -+ * It is possible that __TASK_UTRACED was added by utrace -+ * while we were __TASK_TRACED and before we take ->siglock -+ * for wake_up_quiescent(), we need to block in this case. -+ * Otherwise this is unnecessary but absolutely harmless. -+ */ -+ schedule(); - } - - tracehook_finish_stop(); --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:17 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:17 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:36 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4390F1287F3; - Thu, 30 Jun 2011 20:23:36 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id v5mzxCjpefBI; Thu, 30 Jun 2011 20:23:36 -0400 (EDT) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 283B21287DD; - Thu, 30 Jun 2011 20:23:36 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NSc9032626; - Thu, 30 Jun 2011 20:23:29 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:36 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:34 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 12/19] get_signal_to_deliver: restructure utrace/ptrace - signal reporting -Message-ID: <20110701002134.GA25834@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 2012 -Lines: 73 - -get_signal_to_deliver() assumes that either tracehook_get_signal() does -nothing (without CONFIG_UTRACE), or it also reports the signal to ptrace -engine implemented on top of utrace. Now that ptrace works independently -this doesn't work. - -Change the code to call ptrace_signal() after tracehook_get_signal(). - -Move ->ptrace check from ptrace_signal() to get_signal_to_deliver(), -we do not want to change *return_ka if it was initialized by utrace -and the task is not traced. - -IOW, roughly, ptrace acts as if it is the last attached engine, it -takes the final decision about the signal. - -Signed-off-by: Oleg Nesterov ---- - kernel/signal.c | 24 +++++++++++------------- - 1 files changed, 11 insertions(+), 13 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index 89e691d..d0e0c67 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -2006,9 +2006,6 @@ retry: - static int ptrace_signal(int signr, siginfo_t *info, - struct pt_regs *regs, void *cookie) - { -- if (!task_ptrace(current)) -- return signr; -- - ptrace_signal_deliver(regs, cookie); - - /* Let the debugger run. */ -@@ -2110,6 +2107,7 @@ relock: - signr = tracehook_get_signal(current, regs, info, return_ka); - if (unlikely(signr < 0)) - goto relock; -+ - if (unlikely(signr != 0)) - ka = return_ka; - else { -@@ -2117,18 +2115,18 @@ relock: - GROUP_STOP_PENDING) && do_signal_stop(0)) - goto relock; - -- signr = dequeue_signal(current, ¤t->blocked, -- info); -+ signr = dequeue_signal(current, ¤t->blocked, info); - -- if (!signr) -- break; /* will return 0 */ -+ ka = &sighand->action[signr-1]; -+ } - -- if (signr != SIGKILL) { -- signr = ptrace_signal(signr, info, -- regs, cookie); -- if (!signr) -- continue; -- } -+ if (!signr) -+ break; /* will return 0 */ -+ -+ if (signr != SIGKILL && current->ptrace) { -+ signr = ptrace_signal(signr, info, regs, cookie); -+ if (!signr) -+ continue; - - ka = &sighand->action[signr-1]; - } --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:18 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:18 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:39 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 74BDFD813B; - Thu, 30 Jun 2011 20:23:39 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id tAGkG+GCPdeN; Thu, 30 Jun 2011 20:23:39 -0400 (EDT) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5B728D812A; - Thu, 30 Jun 2011 20:23:39 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NWY1032629; - Thu, 30 Jun 2011 20:23:32 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:39 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:37 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 13/19] introduce ptrace_set_syscall_trace() -Message-ID: <20110701002137.GA25837@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 1581 -Lines: 52 - -No functional changes. Add the new helper, ptrace_set_syscall_trace(), -which should be used to set/clear TIF_SYSCALL_TRACE in ptrace code. -Currently it does nothing more. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 15 ++++++++++----- - 1 files changed, 10 insertions(+), 5 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 0b2aba5..b6fd922 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -37,6 +37,14 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - kick_process(p); - } - -+static void ptrace_set_syscall_trace(struct task_struct *p, bool on) -+{ -+ if (on) -+ set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ else -+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+} -+ - /* - * ptrace a task: make the debugger its new parent and - * move it to the ptrace list. -@@ -364,7 +372,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) - - /* Architecture-specific hardware disable .. */ - ptrace_disable(child); -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, false); - - write_lock_irq(&tasklist_lock); - /* -@@ -551,10 +559,7 @@ static int ptrace_resume(struct task_struct *child, long request, - if (!valid_signal(data)) - return -EIO; - -- if (request == PTRACE_SYSCALL) -- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -- else -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, request == PTRACE_SYSCALL); - - #ifdef TIF_SYSCALL_EMU - if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:20 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:20 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:42 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id CFC3F9C0C5; - Thu, 30 Jun 2011 20:23:42 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id vS4KlM5ek+bt; Thu, 30 Jun 2011 20:23:42 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B28CA9C0C3; - Thu, 30 Jun 2011 20:23:42 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NZvo015255; - Thu, 30 Jun 2011 20:23:35 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:43 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:40 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 14/19] introduce PT_SYSCALL_TRACE flag -Message-ID: <20110701002140.GA25844@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 2236 -Lines: 73 - -Currently tracehooks assume that if the ptraced task has -TIF_SYSCALL_TRACE set, the tracee should report the syscall. -This is not true, this thread flag can be set by utrace. - -Add the new internal ptrace flag, PT_SYSCALL_TRACE. Change -ptrace_set_syscall_trace() to set/clear this bit along with -TIF_SYSCALL_TRACE, change ptrace_report_syscall() to check -this flag instead of PT_PTRACED. - -Signed-off-by: Oleg Nesterov ---- - include/linux/ptrace.h | 3 +++ - include/linux/tracehook.h | 2 +- - kernel/ptrace.c | 7 +++++-- - 3 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 9178d5c..98d995d 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -90,6 +90,8 @@ - - #define PT_TRACE_MASK 0x000003f4 - -+#define PT_SYSCALL_TRACE 0x00010000 -+ - /* single stepping state bits (used on ARM and PA-RISC) */ - #define PT_SINGLESTEP_BIT 31 - #define PT_SINGLESTEP (1<ptrace = 0; - if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) { - child->ptrace = current->ptrace; -+ child->ptrace &= ~PT_SYSCALL_TRACE; - __ptrace_link(child, current->parent); - } - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 3c7b6b3..6ce7a37 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -76,7 +76,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - { - int ptrace = task_ptrace(current); - -- if (!(ptrace & PT_PTRACED)) -+ if (!(ptrace & PT_SYSCALL_TRACE)) - return; - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index b6fd922..0825a01 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -39,10 +39,13 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - - static void ptrace_set_syscall_trace(struct task_struct *p, bool on) - { -- if (on) -+ if (on) { -+ p->ptrace |= PT_SYSCALL_TRACE; - set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -- else -+ } else { -+ p->ptrace &= ~PT_SYSCALL_TRACE; - clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ } - } - - /* --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:21 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:21 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:46 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 35A70D812A; - Thu, 30 Jun 2011 20:23:46 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id L06hkGLA8FQs; Thu, 30 Jun 2011 20:23:46 -0400 (EDT) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 21C2BD810F; - Thu, 30 Jun 2011 20:23:46 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610Nc7k007721; - Thu, 30 Jun 2011 20:23:39 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:46 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:44 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 15/19] utrace: don't clear TIF_SYSCALL_TRACE if it is - needed by ptrace -Message-ID: <20110701002144.GA25847@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 797 -Lines: 24 - -TIF_SYSCALL_TRACE should be cleared only if both ptrace and utrace do -not want it, change utrace_reset() to check PT_SYSCALL_TRACE before -clear_tsk_thread_flag(TIF_SYSCALL_TRACE). - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index daa96b9..a824ac3 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -697,6 +697,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - BUG_ON(utrace->death); - flags &= UTRACE_EVENT(REAP); - } else if (!(flags & UTRACE_EVENT_SYSCALL) && -+ !(task->ptrace & PT_SYSCALL_TRACE) && - test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { - clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); - } --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:22 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:22 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:49 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 72E0C9C0C3; - Thu, 30 Jun 2011 20:23:49 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id o3ezwgloxuCS; Thu, 30 Jun 2011 20:23:49 -0400 (EDT) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5DD6A9C0C5; - Thu, 30 Jun 2011 20:23:49 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610NglX026379; - Thu, 30 Jun 2011 20:23:42 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:49 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:47 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 16/19] introduce task_utrace_lock/task_utrace_unlock -Message-ID: <20110701002147.GA25854@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 2190 -Lines: 81 - -- Add task_utrace_lock(task). It simply takes task->utrace->lock if - this task was ever utraced. Otherwise it takes task_lock(), this - serializes with utrace_attach_task()->utrace_task_alloc(). In both - case the caller can be sure it can't race with anything which needs - utrace->lock. - -- Add task_utrace_unlock(task), it releases the corresponding lock. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 9 +++++++++ - kernel/utrace.c | 26 ++++++++++++++++++++++++++ - 2 files changed, 35 insertions(+), 0 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index f251efe..5176f5f 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -109,6 +109,12 @@ void utrace_signal_handler(struct task_struct *, int); - - #ifndef CONFIG_UTRACE - -+static inline void task_utrace_lock(struct task_struct *task) -+{ -+} -+static inline void task_utrace_unlock(struct task_struct *task) -+{ -+} - /* - * uses these accessors to avoid #ifdef CONFIG_UTRACE. - */ -@@ -131,6 +137,9 @@ static inline void task_utrace_proc_status(struct seq_file *m, - - #else /* CONFIG_UTRACE */ - -+extern void task_utrace_lock(struct task_struct *task); -+extern void task_utrace_unlock(struct task_struct *task); -+ - static inline unsigned long task_utrace_flags(struct task_struct *task) - { - return task->utrace_flags; -diff --git a/kernel/utrace.c b/kernel/utrace.c -index a824ac3..508c13c 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -79,6 +79,32 @@ static int __init utrace_init(void) - } - module_init(utrace_init); - -+void task_utrace_lock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (!utrace) { -+ task_lock(task); -+ utrace = task_utrace_struct(task); -+ if (!utrace) -+ return; -+ -+ task_unlock(task); -+ } -+ -+ spin_lock(&utrace->lock); -+} -+ -+void task_utrace_unlock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace) -+ spin_unlock(&utrace->lock); -+ else -+ task_unlock(task); -+} -+ - /* - * Set up @task.utrace for the first time. We can have races - * between two utrace_attach_task() calls here. The task_lock() --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:24 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:24 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:52 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id DB8D8D812A; - Thu, 30 Jun 2011 20:23:52 -0400 (EDT) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 74TDLZXBCl6s; Thu, 30 Jun 2011 20:23:52 -0400 (EDT) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C6776D810F; - Thu, 30 Jun 2011 20:23:52 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NjAl015271; - Thu, 30 Jun 2011 20:23:45 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:53 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:50 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 17/19] teach ptrace_set_syscall_trace() to play well with - utrace -Message-ID: <20110701002150.GA25861@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 1513 -Lines: 49 - -1. ptrace_set_syscall_trace(true)->set_tsk_thread_flag(TIF_SYSCALL_TRACE) - can race with utrace_control()->utrace_reset() path which can miss - PT_SYSCALL_TRACE and clear TIF_SYSCALL_TRACE after it was already set. - -2. ptrace_set_syscall_trace(false) clears TIF_SYSCALL_TRACE and this is - not utrace-friendly, it can need this flag. - -Change ptrace_set_syscall_trace() to take task_utrace_lock(), this is -enough to fix the 1st problem. Check task_utrace_flags() before clearing -TIF_SYSCALL_TRACE, this fixes 2. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 6 +++++- - 1 files changed, 5 insertions(+), 1 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 0825a01..209ea2d 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - { -@@ -39,13 +40,16 @@ static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - - static void ptrace_set_syscall_trace(struct task_struct *p, bool on) - { -+ task_utrace_lock(p); - if (on) { - p->ptrace |= PT_SYSCALL_TRACE; - set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); - } else { - p->ptrace &= ~PT_SYSCALL_TRACE; -- clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL)) -+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); - } -+ task_utrace_unlock(p); - } - - /* --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:24 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:24 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:56 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6CD231287F3; - Thu, 30 Jun 2011 20:23:56 -0400 (EDT) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id XX9YNcTcP1Ny; Thu, 30 Jun 2011 20:23:56 -0400 (EDT) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 504BF1287DD; - Thu, 30 Jun 2011 20:23:56 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id p610NmjB032686; - Thu, 30 Jun 2011 20:23:49 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:56 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:54 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 18/19] introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK -Message-ID: <20110701002154.GA25864@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 3725 -Lines: 108 - -Add the new internal ptrace flags, PT_SINGLE_STEP and PT_SINGLE_BLOCK. - -Like PT_SYSCALL_TRACE, this is needed to avoid the unnecessary ptrace -reports when TIF_SINGLESTEP was set by another engine, not by ptrace. -Also, we need these bits to coordinate the user_*_single_step() calls -from ptrace and utrace. - -TODO: update the !x86 ptrace code which does user_disable_single_step(). - -Signed-off-by: Oleg Nesterov ---- - arch/x86/kernel/ptrace.c | 1 + - include/linux/ptrace.h | 5 ++++- - include/linux/tracehook.h | 7 +++++-- - kernel/ptrace.c | 3 +++ - 4 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index 807c2a2..7ab475f 100644 ---- a/arch/x86/kernel/ptrace.c -+++ b/arch/x86/kernel/ptrace.c -@@ -807,6 +807,7 @@ static int ioperm_get(struct task_struct *target, - */ - void ptrace_disable(struct task_struct *child) - { -+ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); - user_disable_single_step(child); - #ifdef TIF_SYSCALL_EMU - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 98d995d..65b1e4f 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -91,6 +91,8 @@ - #define PT_TRACE_MASK 0x000003f4 - - #define PT_SYSCALL_TRACE 0x00010000 -+#define PT_SINGLE_STEP 0x00020000 -+#define PT_SINGLE_BLOCK 0x00040000 - - /* single stepping state bits (used on ARM and PA-RISC) */ - #define PT_SINGLESTEP_BIT 31 -@@ -189,7 +191,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) - child->ptrace = 0; - if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) { - child->ptrace = current->ptrace; -- child->ptrace &= ~PT_SYSCALL_TRACE; -+ child->ptrace &= -+ ~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK); - __ptrace_link(child, current->parent); - } - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 6ce7a37..06edb52 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -121,6 +121,9 @@ static inline __must_check int tracehook_report_syscall_entry( - return 0; - } - -+#define ptrace_wants_step() \ -+ (current->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) -+ - /** - * tracehook_report_syscall_exit - task has just finished a system call - * @regs: user register state of current task -@@ -143,7 +146,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) - utrace_report_syscall_exit(regs); - -- if (step) { -+ if (step && ptrace_wants_step()) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); -@@ -436,7 +439,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - { - if (task_utrace_flags(current)) - utrace_signal_handler(current, stepping); -- if (stepping) -+ if (stepping && ptrace_wants_step()) - ptrace_notify(SIGTRAP); - } - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 209ea2d..44908d0 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -575,13 +575,16 @@ static int ptrace_resume(struct task_struct *child, long request, - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); - #endif - -+ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); - if (is_singleblock(request)) { - if (unlikely(!arch_has_block_step())) - return -EIO; -+ child->ptrace |= PT_SINGLE_BLOCK; - user_enable_block_step(child); - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; -+ child->ptrace |= PT_SINGLE_STEP; - user_enable_single_step(child); - } else { - user_disable_single_step(child); --- -1.5.5.1 - - -From davej Thu Jun 30 20:27:26 2011 -Return-Path: oleg@redhat.com -X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on - gelk.kernelslacker.org -X-Spam-Level: -X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_RP_MATCHES_RCVD, - UNPARSEABLE_RELAY autolearn=ham version=3.3.2 -Received: from mail.corp.redhat.com [10.5.5.51] - by gelk with IMAP (fetchmail-6.3.20) - for (single-drop); Thu, 30 Jun 2011 20:27:26 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - mail04.corp.redhat.com with LMTP; Thu, 30 Jun 2011 20:23:59 -0400 (EDT) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8FF6B9C0C5; - Thu, 30 Jun 2011 20:23:59 -0400 (EDT) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id pNFtYrppMjXf; Thu, 30 Jun 2011 20:23:59 -0400 (EDT) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7C2B89C0C3; - Thu, 30 Jun 2011 20:23:59 -0400 (EDT) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id p610Nqpd026408; - Thu, 30 Jun 2011 20:23:52 -0400 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Fri, 1 Jul 2011 02:21:59 +0200 (CEST) -Date: Fri, 1 Jul 2011 02:21:57 +0200 -From: Oleg Nesterov -To: "Frank Ch. Eigler" , Kyle McMartin , - Dave Jones , Josh Stone , - Matthew Garrett , David Smith -Cc: kernel@lists.fedoraproject.org, utrace-devel@redhat.com -Subject: [PATCH 19/19] utrace: consult PT_SINGLE_STEP/PT_SINGLE_BLOCK - before user_disable_single_step() -Message-ID: <20110701002157.GA25871@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 1150 -Lines: 41 - -- do not do user_enable_block_step() if PT_SINGLE_STEP is set, in this - case ptrace has already called user_enable_single_step() - -- do not do user_disable_single_step() if PT_*_STEP is set, ptrace needs - the stepping - -Unless the tracee is killed this can't race with ptrace, this is called -by the tracee itself. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 6 ++++-- - 1 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 508c13c..d6607cb 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -1828,7 +1828,8 @@ static void finish_resume_report(struct task_struct *task, - - case UTRACE_BLOCKSTEP: - if (likely(arch_has_block_step())) { -- user_enable_block_step(task); -+ if (!(current->ptrace & PT_SINGLE_STEP)) -+ user_enable_block_step(task); - break; - } - -@@ -1856,7 +1857,8 @@ static void finish_resume_report(struct task_struct *task, - case UTRACE_REPORT: - case UTRACE_RESUME: - default: -- user_disable_single_step(task); -+ if (!(current->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK))) -+ user_disable_single_step(task); - break; - } - } --- -1.5.5.1 - - diff --git a/weird-root-dentry-name-debug.patch b/weird-root-dentry-name-debug.patch new file mode 100644 index 000000000..e2fb2e116 --- /dev/null +++ b/weird-root-dentry-name-debug.patch @@ -0,0 +1,19 @@ +debug patch for bz 787171/766277 + +diff --git a/fs/dcache.c b/fs/dcache.c +index bcbdb33..a6a5fdb 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2530,8 +2530,10 @@ global_root: + */ + if (IS_ROOT(dentry) && + (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { +- WARN(1, "Root dentry has weird name <%.*s>\n", +- (int) dentry->d_name.len, dentry->d_name.name); ++ WARN(1, "Root dentry has weird name <%.*s> vfsmnt:%s fs:%s\n", ++ (int) dentry->d_name.len, dentry->d_name.name, ++ vfsmnt->mnt_root->d_name.name, ++ vfsmnt->mnt_sb->s_type->name); + } + if (!slash) + error = prepend(buffer, buflen, "/", 1); diff --git a/x86-msr-Add-capabilities-check.patch b/x86-msr-Add-capabilities-check.patch new file mode 100644 index 000000000..a3dc0e532 --- /dev/null +++ b/x86-msr-Add-capabilities-check.patch @@ -0,0 +1,54 @@ +From b9f93c7550b62939f250fad55b111637b0f66bc8 Mon Sep 17 00:00:00 2001 +From: Alan Cox +Date: Thu, 15 Nov 2012 13:06:22 +0000 +Subject: [PATCH] x86/msr: Add capabilities check + +commit c903f0456bc69176912dee6dd25c6a66ee1aed00 upstream. + +At the moment the MSR driver only relies upon file system +checks. This means that anything as root with any capability set +can write to MSRs. Historically that wasn't very interesting but +on modern processors the MSRs are such that writing to them +provides several ways to execute arbitary code in kernel space. +Sample code and documentation on doing this is circulating and +MSR attacks are used on Windows 64bit rootkits already. + +In the Linux case you still need to be able to open the device +file so the impact is fairly limited and reduces the security of +some capability and security model based systems down towards +that of a generic "root owns the box" setup. + +Therefore they should require CAP_SYS_RAWIO to prevent an +elevation of capabilities. The impact of this is fairly minimal +on most setups because they don't have heavy use of +capabilities. Those using SELinux, SMACK or AppArmor rules might +want to consider if their rulesets on the MSR driver could be +tighter. + +Signed-off-by: Alan Cox +Cc: Linus Torvalds +Cc: Andrew Morton +Cc: Peter Zijlstra +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/msr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c +index a7c5661..4929502 100644 +--- a/arch/x86/kernel/msr.c ++++ b/arch/x86/kernel/msr.c +@@ -174,6 +174,9 @@ static int msr_open(struct inode *inode, struct file *file) + unsigned int cpu; + struct cpuinfo_x86 *c; + ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ + cpu = iminor(file->f_path.dentry->d_inode); + if (cpu >= nr_cpu_ids || !cpu_online(cpu)) + return -ENXIO; /* No such CPU */ +-- +1.8.1 + diff --git a/xen-fix-stack-corruption-in-xen_failsafe_callback.patch b/xen-fix-stack-corruption-in-xen_failsafe_callback.patch new file mode 100644 index 000000000..9d83ea0c9 --- /dev/null +++ b/xen-fix-stack-corruption-in-xen_failsafe_callback.patch @@ -0,0 +1,62 @@ +From 38174c8c07ad638cd18285ba402b59076849dc21 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Thu, 10 Jan 2013 17:16:30 +0000 +Subject: [PATCH] xen: Fix stack corruption in xen_failsafe_callback for 32bit PVOPS guests. + +There has been an error on the xen_failsafe_callback path for failed +iret, which causes the stack pointer to be wrong when entering the +iret_exc error path. This can result in the kernel crashing. + +In the classic kernel case, the relevant code looked a little like: + + popl %eax # Error code from hypervisor + jz 5f + addl $16,%esp + jmp iret_exc # Hypervisor said iret fault +5: addl $16,%esp + # Hypervisor said segment selector fault + +Here, there are two identical addls on either option of a branch which +appears to have been optimised by hoisting it above the jz, and +converting it to an lea, which leaves the flags register unaffected. + +In the PVOPS case, the code looks like: + + popl_cfi %eax # Error from the hypervisor + lea 16(%esp),%esp # Add $16 before choosing fault path + CFI_ADJUST_CFA_OFFSET -16 + jz 5f + addl $16,%esp # Incorrectly adjust %esp again + jmp iret_exc + +It is possible unprivileged userspace applications to cause this +behaviour, for example by loading an LDT code selector, then changing +the code selector to be not-present. At this point, there is a race +condition where it is possible for the hypervisor to return back to +userspace from an interrupt, fault on its own iret, and inject a +failsafe_callback into the kernel. + +This bug has been present since the introduction of Xen PVOPS support +in commit 5ead97c84 (xen: Core Xen implementation), in 2.6.23. + +Signed-off-by: Frediano Ziglio +Signed-off-by: Andrew Cooper +--- + arch/x86/kernel/entry_32.S | 1 - + 1 files changed, 0 insertions(+), 1 deletions(-) + +diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S +index ff84d54..6ed91d9 100644 +--- a/arch/x86/kernel/entry_32.S ++++ b/arch/x86/kernel/entry_32.S +@@ -1065,7 +1065,6 @@ ENTRY(xen_failsafe_callback) + lea 16(%esp),%esp + CFI_ADJUST_CFA_OFFSET -16 + jz 5f +- addl $16,%esp + jmp iret_exc + 5: pushl_cfi $-1 /* orig_ax = -1 => not a system call */ + SAVE_ALL +-- +1.7.2.5 +